diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..e63f17f7 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +examples.aedt.docs.pyansys.com diff --git a/index.html b/index.html new file mode 100644 index 00000000..50c27e1d --- /dev/null +++ b/index.html @@ -0,0 +1,10 @@ + + + + + Redirecting to https://examples.aedt.docs.pyansys.com/version/dev/ + + + + + diff --git a/version/dev/_images/CFD_coil.png b/version/dev/_images/CFD_coil.png new file mode 100644 index 00000000..3de4b2fd Binary files /dev/null and b/version/dev/_images/CFD_coil.png differ diff --git a/version/dev/_images/TEAM.png b/version/dev/_images/TEAM.png new file mode 100644 index 00000000..cfc087a2 Binary files /dev/null and b/version/dev/_images/TEAM.png differ diff --git a/version/dev/_images/ac_q3d.png b/version/dev/_images/ac_q3d.png new file mode 100644 index 00000000..501bd578 Binary files /dev/null and b/version/dev/_images/ac_q3d.png differ diff --git a/version/dev/_images/aedt.png b/version/dev/_images/aedt.png new file mode 100644 index 00000000..e7213e3e Binary files /dev/null and b/version/dev/_images/aedt.png differ diff --git a/version/dev/_images/aedt_electronics.png b/version/dev/_images/aedt_electronics.png new file mode 100644 index 00000000..7dbf797a Binary files /dev/null and b/version/dev/_images/aedt_electronics.png differ diff --git a/version/dev/_images/ami.png b/version/dev/_images/ami.png new file mode 100644 index 00000000..d5585a98 Binary files /dev/null and b/version/dev/_images/ami.png differ diff --git a/version/dev/_images/armoured.png b/version/dev/_images/armoured.png new file mode 100644 index 00000000..8b42e319 Binary files /dev/null and b/version/dev/_images/armoured.png differ diff --git a/version/dev/_images/array.png b/version/dev/_images/array.png new file mode 100644 index 00000000..607705a5 Binary files /dev/null and b/version/dev/_images/array.png differ diff --git a/version/dev/_images/asymmetric_conductor.png b/version/dev/_images/asymmetric_conductor.png new file mode 100644 index 00000000..555d4534 Binary files /dev/null and b/version/dev/_images/asymmetric_conductor.png differ diff --git a/version/dev/_images/automatic_report.png b/version/dev/_images/automatic_report.png new file mode 100644 index 00000000..e8ba6df5 Binary files /dev/null and b/version/dev/_images/automatic_report.png differ diff --git a/version/dev/_images/bath.png b/version/dev/_images/bath.png new file mode 100644 index 00000000..a1b470da Binary files /dev/null and b/version/dev/_images/bath.png differ diff --git a/version/dev/_images/bdf.png b/version/dev/_images/bdf.png new file mode 100644 index 00000000..ad9a532a Binary files /dev/null and b/version/dev/_images/bdf.png differ diff --git a/version/dev/_images/busbar.png b/version/dev/_images/busbar.png new file mode 100644 index 00000000..ab9fdbd7 Binary files /dev/null and b/version/dev/_images/busbar.png differ diff --git a/version/dev/_images/car_w_pedestrians.png b/version/dev/_images/car_w_pedestrians.png new file mode 100644 index 00000000..ae55f7de Binary files /dev/null and b/version/dev/_images/car_w_pedestrians.png differ diff --git a/version/dev/_images/charging.png b/version/dev/_images/charging.png new file mode 100644 index 00000000..7ab53d50 Binary files /dev/null and b/version/dev/_images/charging.png differ diff --git a/version/dev/_images/choke.png b/version/dev/_images/choke.png new file mode 100644 index 00000000..92574943 Binary files /dev/null and b/version/dev/_images/choke.png differ diff --git a/version/dev/_images/choke1.png b/version/dev/_images/choke1.png new file mode 100644 index 00000000..92574943 Binary files /dev/null and b/version/dev/_images/choke1.png differ diff --git a/version/dev/_images/circuit.png b/version/dev/_images/circuit.png new file mode 100644 index 00000000..60919670 Binary files /dev/null and b/version/dev/_images/circuit.png differ diff --git a/version/dev/_images/circuit_transient.png b/version/dev/_images/circuit_transient.png new file mode 100644 index 00000000..28b02a0d Binary files /dev/null and b/version/dev/_images/circuit_transient.png differ diff --git a/version/dev/_images/city.png b/version/dev/_images/city.png new file mode 100644 index 00000000..359383f1 Binary files /dev/null and b/version/dev/_images/city.png differ diff --git a/version/dev/_images/coaxial.png b/version/dev/_images/coaxial.png new file mode 100644 index 00000000..4eefdded Binary files /dev/null and b/version/dev/_images/coaxial.png differ diff --git a/version/dev/_images/com_eye.png b/version/dev/_images/com_eye.png new file mode 100644 index 00000000..d29a019d Binary files /dev/null and b/version/dev/_images/com_eye.png differ diff --git a/version/dev/_images/com_report.png b/version/dev/_images/com_report.png new file mode 100644 index 00000000..93661ef0 Binary files /dev/null and b/version/dev/_images/com_report.png differ diff --git a/version/dev/_images/component.png b/version/dev/_images/component.png new file mode 100644 index 00000000..7a4e5eed Binary files /dev/null and b/version/dev/_images/component.png differ diff --git a/version/dev/_images/component_3d.png b/version/dev/_images/component_3d.png new file mode 100644 index 00000000..1719286c Binary files /dev/null and b/version/dev/_images/component_3d.png differ diff --git a/version/dev/_images/components.png b/version/dev/_images/components.png new file mode 100644 index 00000000..a644387c Binary files /dev/null and b/version/dev/_images/components.png differ diff --git a/version/dev/_images/configuration_file_icepak.png b/version/dev/_images/configuration_file_icepak.png new file mode 100644 index 00000000..df0eb49e Binary files /dev/null and b/version/dev/_images/configuration_file_icepak.png differ diff --git a/version/dev/_images/control_program.png b/version/dev/_images/control_program.png new file mode 100644 index 00000000..e64ee23a Binary files /dev/null and b/version/dev/_images/control_program.png differ diff --git a/version/dev/_images/coordinate_system.png b/version/dev/_images/coordinate_system.png new file mode 100644 index 00000000..eb887c92 Binary files /dev/null and b/version/dev/_images/coordinate_system.png differ diff --git a/version/dev/_images/coupling.png b/version/dev/_images/coupling.png new file mode 100644 index 00000000..865600cc Binary files /dev/null and b/version/dev/_images/coupling.png differ diff --git a/version/dev/_images/cpwg.png b/version/dev/_images/cpwg.png new file mode 100644 index 00000000..6c6f4e7c Binary files /dev/null and b/version/dev/_images/cpwg.png differ diff --git a/version/dev/_images/dc.png b/version/dev/_images/dc.png new file mode 100644 index 00000000..ff3fa23b Binary files /dev/null and b/version/dev/_images/dc.png differ diff --git a/version/dev/_images/dcir.png b/version/dev/_images/dcir.png new file mode 100644 index 00000000..7711754d Binary files /dev/null and b/version/dev/_images/dcir.png differ diff --git a/version/dev/_images/dcir_q3d.png b/version/dev/_images/dcir_q3d.png new file mode 100644 index 00000000..c1bb59c5 Binary files /dev/null and b/version/dev/_images/dcir_q3d.png differ diff --git a/version/dev/_images/dipole.png b/version/dev/_images/dipole.png new file mode 100644 index 00000000..c8f46976 Binary files /dev/null and b/version/dev/_images/dipole.png differ diff --git a/version/dev/_images/doppler.png b/version/dev/_images/doppler.png new file mode 100644 index 00000000..bd47d4b3 Binary files /dev/null and b/version/dev/_images/doppler.png differ diff --git a/version/dev/_images/dynamic_rom_plot.png b/version/dev/_images/dynamic_rom_plot.png new file mode 100644 index 00000000..15e4b316 Binary files /dev/null and b/version/dev/_images/dynamic_rom_plot.png differ diff --git a/version/dev/_images/e3dcomp.png b/version/dev/_images/e3dcomp.png new file mode 100644 index 00000000..37f67883 Binary files /dev/null and b/version/dev/_images/e3dcomp.png differ diff --git a/version/dev/_images/ecad.png b/version/dev/_images/ecad.png new file mode 100644 index 00000000..b561e762 Binary files /dev/null and b/version/dev/_images/ecad.png differ diff --git a/version/dev/_images/eddy_current.png b/version/dev/_images/eddy_current.png new file mode 100644 index 00000000..f354a609 Binary files /dev/null and b/version/dev/_images/eddy_current.png differ diff --git a/version/dev/_images/eigenmode.png b/version/dev/_images/eigenmode.png new file mode 100644 index 00000000..022dc050 Binary files /dev/null and b/version/dev/_images/eigenmode.png differ diff --git a/version/dev/_images/electrostatic.png b/version/dev/_images/electrostatic.png new file mode 100644 index 00000000..e6013dae Binary files /dev/null and b/version/dev/_images/electrostatic.png differ diff --git a/version/dev/_images/electrothermal.png b/version/dev/_images/electrothermal.png new file mode 100644 index 00000000..0f8fc396 Binary files /dev/null and b/version/dev/_images/electrothermal.png differ diff --git a/version/dev/_images/emc.png b/version/dev/_images/emc.png new file mode 100644 index 00000000..1e24c450 Binary files /dev/null and b/version/dev/_images/emc.png differ diff --git a/version/dev/_images/emit.png b/version/dev/_images/emit.png new file mode 100644 index 00000000..685796f5 Binary files /dev/null and b/version/dev/_images/emit.png differ diff --git a/version/dev/_images/emit_hfss.png b/version/dev/_images/emit_hfss.png new file mode 100644 index 00000000..5c771902 Binary files /dev/null and b/version/dev/_images/emit_hfss.png differ diff --git a/version/dev/_images/emit_simple_cosite.png b/version/dev/_images/emit_simple_cosite.png new file mode 100644 index 00000000..a136180a Binary files /dev/null and b/version/dev/_images/emit_simple_cosite.png differ diff --git a/version/dev/_images/emit_simple_cosite1.png b/version/dev/_images/emit_simple_cosite1.png new file mode 100644 index 00000000..a136180a Binary files /dev/null and b/version/dev/_images/emit_simple_cosite1.png differ diff --git a/version/dev/_images/examples_aedt_general_components_reuse_component_39_2.png b/version/dev/_images/examples_aedt_general_components_reuse_component_39_2.png new file mode 100644 index 00000000..1719286c Binary files /dev/null and b/version/dev/_images/examples_aedt_general_components_reuse_component_39_2.png differ diff --git a/version/dev/_images/examples_aedt_general_modeler_circuit_schematic_26_0.png b/version/dev/_images/examples_aedt_general_modeler_circuit_schematic_26_0.png new file mode 100644 index 00000000..ee3e6cdd Binary files /dev/null and b/version/dev/_images/examples_aedt_general_modeler_circuit_schematic_26_0.png differ diff --git a/version/dev/_images/examples_aedt_general_optimetrics_11_2.png b/version/dev/_images/examples_aedt_general_optimetrics_11_2.png new file mode 100644 index 00000000..94e4f472 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_optimetrics_11_2.png differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_11_1.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_11_1.jpg new file mode 100644 index 00000000..aecf90ce Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_11_1.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_13_1.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_13_1.jpg new file mode 100644 index 00000000..85050c20 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_13_1.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_15_1.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_15_1.jpg new file mode 100644 index 00000000..931dbb0e Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_15_1.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_16_1.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_16_1.jpg new file mode 100644 index 00000000..281c72c3 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_16_1.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_7_0.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_7_0.jpg new file mode 100644 index 00000000..ffd24cbb Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_7_0.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_automatic_report_9_1.jpg b/version/dev/_images/examples_aedt_general_report_automatic_report_9_1.jpg new file mode 100644 index 00000000..bbf83b05 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_automatic_report_9_1.jpg differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_10_0.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_0.png new file mode 100644 index 00000000..e82cd482 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_0.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_10_1.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_1.png new file mode 100644 index 00000000..5e040bcf Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_1.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_10_2.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_2.png new file mode 100644 index 00000000..e7a1f188 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_2.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_10_3.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_3.png new file mode 100644 index 00000000..bebef9d5 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_10_3.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_8_0.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_0.png new file mode 100644 index 00000000..fcd2a846 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_0.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_8_1.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_1.png new file mode 100644 index 00000000..f60a0593 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_1.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_8_2.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_2.png new file mode 100644 index 00000000..1299da6e Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_2.png differ diff --git a/version/dev/_images/examples_aedt_general_report_touchstone_file_8_3.png b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_3.png new file mode 100644 index 00000000..cbcfeb59 Binary files /dev/null and b/version/dev/_images/examples_aedt_general_report_touchstone_file_8_3.png differ diff --git a/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_45_2.png b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_45_2.png new file mode 100644 index 00000000..48eb6017 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_45_2.png differ diff --git a/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_47_1.png b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_47_1.png new file mode 100644 index 00000000..4eefdded Binary files /dev/null and b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_47_1.png differ diff --git a/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_1.png b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_1.png new file mode 100644 index 00000000..03d78969 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_1.png differ diff --git a/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_2.png b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_2.png new file mode 100644 index 00000000..03d78969 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_coaxial_hfss_icepak_51_2.png differ diff --git a/version/dev/_images/examples_electrothermal_component_3d_15_2.png b/version/dev/_images/examples_electrothermal_component_3d_15_2.png new file mode 100644 index 00000000..1f2d799e Binary files /dev/null and b/version/dev/_images/examples_electrothermal_component_3d_15_2.png differ diff --git a/version/dev/_images/examples_electrothermal_component_3d_23_2.png b/version/dev/_images/examples_electrothermal_component_3d_23_2.png new file mode 100644 index 00000000..b5e0238e Binary files /dev/null and b/version/dev/_images/examples_electrothermal_component_3d_23_2.png differ diff --git a/version/dev/_images/examples_electrothermal_component_3d_35_2.png b/version/dev/_images/examples_electrothermal_component_3d_35_2.png new file mode 100644 index 00000000..7a4e5eed Binary files /dev/null and b/version/dev/_images/examples_electrothermal_component_3d_35_2.png differ diff --git a/version/dev/_images/examples_electrothermal_component_3d_38_2.png b/version/dev/_images/examples_electrothermal_component_3d_38_2.png new file mode 100644 index 00000000..9e5abff2 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_component_3d_38_2.png differ diff --git a/version/dev/_images/examples_electrothermal_components_csv_20_0.jpg b/version/dev/_images/examples_electrothermal_components_csv_20_0.jpg new file mode 100644 index 00000000..906fd9ee Binary files /dev/null and b/version/dev/_images/examples_electrothermal_components_csv_20_0.jpg differ diff --git a/version/dev/_images/examples_electrothermal_components_csv_29_0.png b/version/dev/_images/examples_electrothermal_components_csv_29_0.png new file mode 100644 index 00000000..24a4df0f Binary files /dev/null and b/version/dev/_images/examples_electrothermal_components_csv_29_0.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_11_2.png b/version/dev/_images/examples_electrothermal_graphic_card_11_2.png new file mode 100644 index 00000000..80f102b4 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_11_2.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_11_4.png b/version/dev/_images/examples_electrothermal_graphic_card_11_4.png new file mode 100644 index 00000000..7535f9e3 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_11_4.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_42_1.png b/version/dev/_images/examples_electrothermal_graphic_card_42_1.png new file mode 100644 index 00000000..f4105aec Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_42_1.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_50_1.png b/version/dev/_images/examples_electrothermal_graphic_card_50_1.png new file mode 100644 index 00000000..cc201116 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_50_1.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_53_0.png b/version/dev/_images/examples_electrothermal_graphic_card_53_0.png new file mode 100644 index 00000000..c800adee Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_53_0.png differ diff --git a/version/dev/_images/examples_electrothermal_graphic_card_55_1.png b/version/dev/_images/examples_electrothermal_graphic_card_55_1.png new file mode 100644 index 00000000..79c21752 Binary files /dev/null and b/version/dev/_images/examples_electrothermal_graphic_card_55_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_array_26_1.png b/version/dev/_images/examples_high_frequency_antenna_array_26_1.png new file mode 100644 index 00000000..413f5d80 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_array_26_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_array_33_1.png b/version/dev/_images/examples_high_frequency_antenna_array_33_1.png new file mode 100644 index 00000000..413f5d80 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_array_33_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_array_35_1.png b/version/dev/_images/examples_high_frequency_antenna_array_35_1.png new file mode 100644 index 00000000..5ac79c2d Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_array_35_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_array_36_1.png b/version/dev/_images/examples_high_frequency_antenna_array_36_1.png new file mode 100644 index 00000000..2dcc7d1c Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_array_36_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_array_38_1.png b/version/dev/_images/examples_high_frequency_antenna_array_38_1.png new file mode 100644 index 00000000..1eaa3097 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_array_38_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_dipole_29_1.png b/version/dev/_images/examples_high_frequency_antenna_dipole_29_1.png new file mode 100644 index 00000000..88bddee2 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_dipole_29_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_dipole_29_2.png b/version/dev/_images/examples_high_frequency_antenna_dipole_29_2.png new file mode 100644 index 00000000..88bddee2 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_dipole_29_2.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_dipole_39_0.png b/version/dev/_images/examples_high_frequency_antenna_dipole_39_0.png new file mode 100644 index 00000000..72d5e68e Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_dipole_39_0.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_dipole_39_1.png b/version/dev/_images/examples_high_frequency_antenna_dipole_39_1.png new file mode 100644 index 00000000..72d5e68e Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_dipole_39_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_dipole_43_1.png b/version/dev/_images/examples_high_frequency_antenna_dipole_43_1.png new file mode 100644 index 00000000..68a32f22 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_dipole_43_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_large_scenarios_city_15_2.png b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_city_15_2.png new file mode 100644 index 00000000..69d8bcae Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_city_15_2.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_1.png b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_1.png new file mode 100644 index 00000000..f1674ccf Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_2.png b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_2.png new file mode 100644 index 00000000..f1674ccf Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_reflector_21_2.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_large_scenarios_time_domain_20_1.png b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_time_domain_20_1.png new file mode 100644 index 00000000..788d3633 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_large_scenarios_time_domain_20_1.png differ diff --git a/version/dev/_images/examples_high_frequency_antenna_patch_15_1.png b/version/dev/_images/examples_high_frequency_antenna_patch_15_1.png new file mode 100644 index 00000000..80776fb5 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_antenna_patch_15_1.png differ diff --git a/version/dev/_images/examples_high_frequency_emc_busbar_12_2.png b/version/dev/_images/examples_high_frequency_emc_busbar_12_2.png new file mode 100644 index 00000000..ab9fdbd7 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_emc_busbar_12_2.png differ diff --git a/version/dev/_images/examples_high_frequency_emc_busbar_26_1.png b/version/dev/_images/examples_high_frequency_emc_busbar_26_1.png new file mode 100644 index 00000000..428c198f Binary files /dev/null and b/version/dev/_images/examples_high_frequency_emc_busbar_26_1.png differ diff --git a/version/dev/_images/examples_high_frequency_emc_busbar_26_2.png b/version/dev/_images/examples_high_frequency_emc_busbar_26_2.png new file mode 100644 index 00000000..428c198f Binary files /dev/null and b/version/dev/_images/examples_high_frequency_emc_busbar_26_2.png differ diff --git a/version/dev/_images/examples_high_frequency_emc_choke_29_2.png b/version/dev/_images/examples_high_frequency_emc_choke_29_2.png new file mode 100644 index 00000000..92574943 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_emc_choke_29_2.png differ diff --git a/version/dev/_images/examples_high_frequency_emc_eigenmode_21_1.png b/version/dev/_images/examples_high_frequency_emc_eigenmode_21_1.png new file mode 100644 index 00000000..022dc050 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_emc_eigenmode_21_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_22_2.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_22_2.png new file mode 100644 index 00000000..5658f307 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_22_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_2.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_2.png new file mode 100644 index 00000000..23634246 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_3.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_3.png new file mode 100644 index 00000000..81f8c44b Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_3.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_4.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_4.png new file mode 100644 index 00000000..23634246 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_ac_q3d_30_4.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_30_1.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_30_1.png new file mode 100644 index 00000000..6e7a727a Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_30_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_26_2.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_26_2.png new file mode 100644 index 00000000..2a1d1945 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_26_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_36_1.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_36_1.png new file mode 100644 index 00000000..367f1bf0 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_dcir_q3d_36_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_1.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_1.png new file mode 100644 index 00000000..5eae3fbf Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_2.png b/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_2.png new file mode 100644 index 00000000..5eae3fbf Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_power_integrity_power_integrity_37_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_16_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_16_0.png new file mode 100644 index 00000000..b760a1be Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_16_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_20_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_20_0.png new file mode 100644 index 00000000..74b86f35 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_20_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_22_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_22_0.png new file mode 100644 index 00000000..de29d672 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_22_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_24_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_24_0.png new file mode 100644 index 00000000..d4e579f6 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_24_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_30_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_30_0.png new file mode 100644 index 00000000..6e2c4fbb Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_30_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_32_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_32_0.png new file mode 100644 index 00000000..82237496 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_ami_32_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_1.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_1.png new file mode 100644 index 00000000..1902d376 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_2.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_2.png new file mode 100644 index 00000000..1902d376 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_22_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_1.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_1.png new file mode 100644 index 00000000..bcb6cb1c Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_2.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_2.png new file mode 100644 index 00000000..bcb6cb1c Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_24_2.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_28_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_28_0.png new file mode 100644 index 00000000..0c11955a Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_circuit_transient_28_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_22_0.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_22_0.png new file mode 100644 index 00000000..9e97fe6b Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_22_0.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_44_1.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_44_1.png new file mode 100644 index 00000000..95d3f511 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_44_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_39_1.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_39_1.png new file mode 100644 index 00000000..e81a9f12 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_39_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_1.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_1.png new file mode 100644 index 00000000..4e6bbc76 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_1.png differ diff --git a/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_2.png b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_2.png new file mode 100644 index 00000000..4e6bbc76 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_layout_signal_integrity_pre_layout_parametrized_51_2.png differ diff --git a/version/dev/_images/examples_high_frequency_multiphysics_mri_23_2.png b/version/dev/_images/examples_high_frequency_multiphysics_mri_23_2.png new file mode 100644 index 00000000..c5cfd488 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_multiphysics_mri_23_2.png differ diff --git a/version/dev/_images/examples_high_frequency_multiphysics_mri_39_2.png b/version/dev/_images/examples_high_frequency_multiphysics_mri_39_2.png new file mode 100644 index 00000000..82afa943 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_multiphysics_mri_39_2.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_1.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_1.png new file mode 100644 index 00000000..83306086 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_1.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_2.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_2.png new file mode 100644 index 00000000..83306086 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_coplanar_waveguide_32_2.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_32_1.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_32_1.png new file mode 100644 index 00000000..4b29c433 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_32_1.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_34_1.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_34_1.png new file mode 100644 index 00000000..6fdb3448 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_iris_filter_34_1.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_29_2.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_29_2.png new file mode 100644 index 00000000..64d2db1c Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_29_2.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_1.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_1.png new file mode 100644 index 00000000..2431ee39 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_1.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_2.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_2.png new file mode 100644 index 00000000..2431ee39 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_spiral_37_2.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_1.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_1.png new file mode 100644 index 00000000..cec0d891 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_1.png differ diff --git a/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_2.png b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_2.png new file mode 100644 index 00000000..cec0d891 Binary files /dev/null and b/version/dev/_images/examples_high_frequency_radiofrequency_mmwave_stripline_41_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_control_program_22_2.png b/version/dev/_images/examples_low_frequency_general_control_program_22_2.png new file mode 100644 index 00000000..37199428 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_control_program_22_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_control_program_22_3.png b/version/dev/_images/examples_low_frequency_general_control_program_22_3.png new file mode 100644 index 00000000..37199428 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_control_program_22_3.png differ diff --git a/version/dev/_images/examples_low_frequency_general_resistance_32_1.png b/version/dev/_images/examples_low_frequency_general_resistance_32_1.png new file mode 100644 index 00000000..96061c0e Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_resistance_32_1.png differ diff --git a/version/dev/_images/examples_low_frequency_general_resistance_36_1.png b/version/dev/_images/examples_low_frequency_general_resistance_36_1.png new file mode 100644 index 00000000..891840e7 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_resistance_36_1.png differ diff --git a/version/dev/_images/examples_low_frequency_general_resistance_38_1.png b/version/dev/_images/examples_low_frequency_general_resistance_38_1.png new file mode 100644 index 00000000..063b09f1 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_resistance_38_1.png differ diff --git a/version/dev/_images/examples_low_frequency_general_resistance_48_2.png b/version/dev/_images/examples_low_frequency_general_resistance_48_2.png new file mode 100644 index 00000000..1ff23b46 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_resistance_48_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_38_2.png b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_38_2.png new file mode 100644 index 00000000..cd714a23 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_38_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_39_2.png b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_39_2.png new file mode 100644 index 00000000..e8a8e090 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_39_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_40_0.png b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_40_0.png new file mode 100644 index 00000000..7681661a Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_dynamic_rom_40_0.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_lti_rom_sml_49_0.png b/version/dev/_images/examples_low_frequency_general_twin_builder_lti_rom_sml_49_0.png new file mode 100644 index 00000000..acfd602d Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_lti_rom_sml_49_0.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_2.png b/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_2.png new file mode 100644 index 00000000..59fd0602 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_2.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_3.png b/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_3.png new file mode 100644 index 00000000..59fd0602 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_rc_circuit_22_3.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_34_1.png b/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_34_1.png new file mode 100644 index 00000000..8cc707e5 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_34_1.png differ diff --git a/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_35_1.png b/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_35_1.png new file mode 100644 index 00000000..ca9487ae Binary files /dev/null and b/version/dev/_images/examples_low_frequency_general_twin_builder_rectifier_35_1.png differ diff --git a/version/dev/_images/examples_low_frequency_magnetic_choke_29_2.png b/version/dev/_images/examples_low_frequency_magnetic_choke_29_2.png new file mode 100644 index 00000000..011242eb Binary files /dev/null and b/version/dev/_images/examples_low_frequency_magnetic_choke_29_2.png differ diff --git a/version/dev/_images/examples_low_frequency_magnetic_transient_winding_23_1.png b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_23_1.png new file mode 100644 index 00000000..e1d29746 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_23_1.png differ diff --git a/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_2.png b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_2.png new file mode 100644 index 00000000..ba828b0c Binary files /dev/null and b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_2.png differ diff --git a/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_3.png b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_3.png new file mode 100644 index 00000000..ba828b0c Binary files /dev/null and b/version/dev/_images/examples_low_frequency_magnetic_transient_winding_25_3.png differ diff --git a/version/dev/_images/examples_low_frequency_motor_aedt_motor_pm_synchronous_83_2.png b/version/dev/_images/examples_low_frequency_motor_aedt_motor_pm_synchronous_83_2.png new file mode 100644 index 00000000..f1dbd8fe Binary files /dev/null and b/version/dev/_images/examples_low_frequency_motor_aedt_motor_pm_synchronous_83_2.png differ diff --git a/version/dev/_images/examples_low_frequency_motor_aedt_motor_rmxpert_26_2.png b/version/dev/_images/examples_low_frequency_motor_aedt_motor_rmxpert_26_2.png new file mode 100644 index 00000000..d70e0c0c Binary files /dev/null and b/version/dev/_images/examples_low_frequency_motor_aedt_motor_rmxpert_26_2.png differ diff --git a/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_0.png b/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_0.png new file mode 100644 index 00000000..4903c7a0 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_0.png differ diff --git a/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_1.png b/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_1.png new file mode 100644 index 00000000..4903c7a0 Binary files /dev/null and b/version/dev/_images/examples_low_frequency_team_problem_bath_plate_40_1.png differ diff --git a/version/dev/_images/external_circuit.png b/version/dev/_images/external_circuit.png new file mode 100644 index 00000000..f1f73bdf Binary files /dev/null and b/version/dev/_images/external_circuit.png differ diff --git a/version/dev/_images/field.png b/version/dev/_images/field.png new file mode 100644 index 00000000..35b73fcc Binary files /dev/null and b/version/dev/_images/field.png differ diff --git a/version/dev/_images/flex_cable.png b/version/dev/_images/flex_cable.png new file mode 100644 index 00000000..79e89379 Binary files /dev/null and b/version/dev/_images/flex_cable.png differ diff --git a/version/dev/_images/general.png b/version/dev/_images/general.png new file mode 100644 index 00000000..24c90dd9 Binary files /dev/null and b/version/dev/_images/general.png differ diff --git a/version/dev/_images/graphic.png b/version/dev/_images/graphic.png new file mode 100644 index 00000000..4b59e22d Binary files /dev/null and b/version/dev/_images/graphic.png differ diff --git a/version/dev/_images/hf.png b/version/dev/_images/hf.png new file mode 100644 index 00000000..556c3083 Binary files /dev/null and b/version/dev/_images/hf.png differ diff --git a/version/dev/_images/hfss_mechanical.png b/version/dev/_images/hfss_mechanical.png new file mode 100644 index 00000000..d5ff1707 Binary files /dev/null and b/version/dev/_images/hfss_mechanical.png differ diff --git a/version/dev/_images/icepak_csv.png b/version/dev/_images/icepak_csv.png new file mode 100644 index 00000000..24a4df0f Binary files /dev/null and b/version/dev/_images/icepak_csv.png differ diff --git a/version/dev/_images/icepak_logo.png b/version/dev/_images/icepak_logo.png new file mode 100644 index 00000000..3ccf55fd Binary files /dev/null and b/version/dev/_images/icepak_logo.png differ diff --git a/version/dev/_images/interference.png b/version/dev/_images/interference.png new file mode 100644 index 00000000..797199e2 Binary files /dev/null and b/version/dev/_images/interference.png differ diff --git a/version/dev/_images/interference_type.png b/version/dev/_images/interference_type.png new file mode 100644 index 00000000..0e38b4d5 Binary files /dev/null and b/version/dev/_images/interference_type.png differ diff --git a/version/dev/_images/ipm_optimization.png b/version/dev/_images/ipm_optimization.png new file mode 100644 index 00000000..ebf8d3bd Binary files /dev/null and b/version/dev/_images/ipm_optimization.png differ diff --git a/version/dev/_images/layout.png b/version/dev/_images/layout.png new file mode 100644 index 00000000..bae41c44 Binary files /dev/null and b/version/dev/_images/layout.png differ diff --git a/version/dev/_images/ldf.png b/version/dev/_images/ldf.png new file mode 100644 index 00000000..43646374 Binary files /dev/null and b/version/dev/_images/ldf.png differ diff --git a/version/dev/_images/logo.png b/version/dev/_images/logo.png new file mode 100644 index 00000000..e0d70667 Binary files /dev/null and b/version/dev/_images/logo.png differ diff --git a/version/dev/_images/lorentz_actuator.png b/version/dev/_images/lorentz_actuator.png new file mode 100644 index 00000000..f6be0c6a Binary files /dev/null and b/version/dev/_images/lorentz_actuator.png differ diff --git a/version/dev/_images/lti_rom.png b/version/dev/_images/lti_rom.png new file mode 100644 index 00000000..e8716246 Binary files /dev/null and b/version/dev/_images/lti_rom.png differ diff --git a/version/dev/_images/lumped_filter.png b/version/dev/_images/lumped_filter.png new file mode 100644 index 00000000..b97f4f0a Binary files /dev/null and b/version/dev/_images/lumped_filter.png differ diff --git a/version/dev/_images/magnet_segmentation.png b/version/dev/_images/magnet_segmentation.png new file mode 100644 index 00000000..eb9f5302 Binary files /dev/null and b/version/dev/_images/magnet_segmentation.png differ diff --git a/version/dev/_images/magnetic.png b/version/dev/_images/magnetic.png new file mode 100644 index 00000000..f812ba0b Binary files /dev/null and b/version/dev/_images/magnetic.png differ diff --git a/version/dev/_images/magneto.png b/version/dev/_images/magneto.png new file mode 100644 index 00000000..3e6889ce Binary files /dev/null and b/version/dev/_images/magneto.png differ diff --git a/version/dev/_images/modeler.png b/version/dev/_images/modeler.png new file mode 100644 index 00000000..6f3c1a73 Binary files /dev/null and b/version/dev/_images/modeler.png differ diff --git a/version/dev/_images/motor.png b/version/dev/_images/motor.png new file mode 100644 index 00000000..bb00973c Binary files /dev/null and b/version/dev/_images/motor.png differ diff --git a/version/dev/_images/motor_maxwell.png b/version/dev/_images/motor_maxwell.png new file mode 100644 index 00000000..b0f49570 Binary files /dev/null and b/version/dev/_images/motor_maxwell.png differ diff --git a/version/dev/_images/motorcad.png b/version/dev/_images/motorcad.png new file mode 100644 index 00000000..b835d8fb Binary files /dev/null and b/version/dev/_images/motorcad.png differ diff --git a/version/dev/_images/mri.png b/version/dev/_images/mri.png new file mode 100644 index 00000000..c5cfd488 Binary files /dev/null and b/version/dev/_images/mri.png differ diff --git a/version/dev/_images/multizone.png b/version/dev/_images/multizone.png new file mode 100644 index 00000000..d040d3d1 Binary files /dev/null and b/version/dev/_images/multizone.png differ diff --git a/version/dev/_images/netlist.png b/version/dev/_images/netlist.png new file mode 100644 index 00000000..0f975446 Binary files /dev/null and b/version/dev/_images/netlist.png differ diff --git a/version/dev/_images/optimetrics.png b/version/dev/_images/optimetrics.png new file mode 100644 index 00000000..96721586 Binary files /dev/null and b/version/dev/_images/optimetrics.png differ diff --git a/version/dev/_images/patch.png b/version/dev/_images/patch.png new file mode 100644 index 00000000..c3a48eb3 Binary files /dev/null and b/version/dev/_images/patch.png differ diff --git a/version/dev/_images/pcb_stress.png b/version/dev/_images/pcb_stress.png new file mode 100644 index 00000000..5b1e260c Binary files /dev/null and b/version/dev/_images/pcb_stress.png differ diff --git a/version/dev/_images/pm_synchronous.png b/version/dev/_images/pm_synchronous.png new file mode 100644 index 00000000..ab8a4f3a Binary files /dev/null and b/version/dev/_images/pm_synchronous.png differ diff --git a/version/dev/_images/polyline.png b/version/dev/_images/polyline.png new file mode 100644 index 00000000..0390f434 Binary files /dev/null and b/version/dev/_images/polyline.png differ diff --git a/version/dev/_images/power_integrity.png b/version/dev/_images/power_integrity.png new file mode 100644 index 00000000..57ec77ca Binary files /dev/null and b/version/dev/_images/power_integrity.png differ diff --git a/version/dev/_images/power_integrity1.png b/version/dev/_images/power_integrity1.png new file mode 100644 index 00000000..7ee1c35d Binary files /dev/null and b/version/dev/_images/power_integrity1.png differ diff --git a/version/dev/_images/pre_layout_parameterized_pcb.png b/version/dev/_images/pre_layout_parameterized_pcb.png new file mode 100644 index 00000000..f75d4a2e Binary files /dev/null and b/version/dev/_images/pre_layout_parameterized_pcb.png differ diff --git a/version/dev/_images/pre_layout_sma_connector_on_pcb.png b/version/dev/_images/pre_layout_sma_connector_on_pcb.png new file mode 100644 index 00000000..6e921c69 Binary files /dev/null and b/version/dev/_images/pre_layout_sma_connector_on_pcb.png differ diff --git a/version/dev/_images/protection.png b/version/dev/_images/protection.png new file mode 100644 index 00000000..1c69ad1f Binary files /dev/null and b/version/dev/_images/protection.png differ diff --git a/version/dev/_images/pyedb.png b/version/dev/_images/pyedb.png new file mode 100644 index 00000000..d444d1cc Binary files /dev/null and b/version/dev/_images/pyedb.png differ diff --git a/version/dev/_images/pyedb2.png b/version/dev/_images/pyedb2.png new file mode 100644 index 00000000..99187454 Binary files /dev/null and b/version/dev/_images/pyedb2.png differ diff --git a/version/dev/_images/rc.png b/version/dev/_images/rc.png new file mode 100644 index 00000000..d0244927 Binary files /dev/null and b/version/dev/_images/rc.png differ diff --git a/version/dev/_images/rectifier.png b/version/dev/_images/rectifier.png new file mode 100644 index 00000000..eebc301b Binary files /dev/null and b/version/dev/_images/rectifier.png differ diff --git a/version/dev/_images/rectifier_response.png b/version/dev/_images/rectifier_response.png new file mode 100644 index 00000000..ca9487ae Binary files /dev/null and b/version/dev/_images/rectifier_response.png differ diff --git a/version/dev/_images/reflector.png b/version/dev/_images/reflector.png new file mode 100644 index 00000000..1a2b5283 Binary files /dev/null and b/version/dev/_images/reflector.png differ diff --git a/version/dev/_images/resistance.png b/version/dev/_images/resistance.png new file mode 100644 index 00000000..c0f27a8d Binary files /dev/null and b/version/dev/_images/resistance.png differ diff --git a/version/dev/_images/ring.png b/version/dev/_images/ring.png new file mode 100644 index 00000000..cfb5cc20 Binary files /dev/null and b/version/dev/_images/ring.png differ diff --git a/version/dev/_images/rmxpert.png b/version/dev/_images/rmxpert.png new file mode 100644 index 00000000..1a930682 Binary files /dev/null and b/version/dev/_images/rmxpert.png differ diff --git a/version/dev/_images/sherlock.png b/version/dev/_images/sherlock.png new file mode 100644 index 00000000..a3206d22 Binary files /dev/null and b/version/dev/_images/sherlock.png differ diff --git a/version/dev/_images/signal_integrity.png b/version/dev/_images/signal_integrity.png new file mode 100644 index 00000000..08a183b1 Binary files /dev/null and b/version/dev/_images/signal_integrity.png differ diff --git a/version/dev/_images/spiral.png b/version/dev/_images/spiral.png new file mode 100644 index 00000000..36e2ff2c Binary files /dev/null and b/version/dev/_images/spiral.png differ diff --git a/version/dev/_images/static_rom.png b/version/dev/_images/static_rom.png new file mode 100644 index 00000000..1df47a81 Binary files /dev/null and b/version/dev/_images/static_rom.png differ diff --git a/version/dev/_images/stripline.png b/version/dev/_images/stripline.png new file mode 100644 index 00000000..ab70d8ad Binary files /dev/null and b/version/dev/_images/stripline.png differ diff --git a/version/dev/_images/subcircuit.png b/version/dev/_images/subcircuit.png new file mode 100644 index 00000000..86686eef Binary files /dev/null and b/version/dev/_images/subcircuit.png differ diff --git a/version/dev/_images/time_domain.png b/version/dev/_images/time_domain.png new file mode 100644 index 00000000..788d3633 Binary files /dev/null and b/version/dev/_images/time_domain.png differ diff --git a/version/dev/_images/touchstone.png b/version/dev/_images/touchstone.png new file mode 100644 index 00000000..800e5d68 Binary files /dev/null and b/version/dev/_images/touchstone.png differ diff --git a/version/dev/_images/touchstone_skitrf.png b/version/dev/_images/touchstone_skitrf.png new file mode 100644 index 00000000..fcd2a846 Binary files /dev/null and b/version/dev/_images/touchstone_skitrf.png differ diff --git a/version/dev/_images/transformer.png b/version/dev/_images/transformer.png new file mode 100644 index 00000000..6ca02cf6 Binary files /dev/null and b/version/dev/_images/transformer.png differ diff --git a/version/dev/_images/transformer2.png b/version/dev/_images/transformer2.png new file mode 100644 index 00000000..cfa28210 Binary files /dev/null and b/version/dev/_images/transformer2.png differ diff --git a/version/dev/_images/transient.png b/version/dev/_images/transient.png new file mode 100644 index 00000000..3d6b48bb Binary files /dev/null and b/version/dev/_images/transient.png differ diff --git a/version/dev/_images/unitcell.png b/version/dev/_images/unitcell.png new file mode 100644 index 00000000..0e214dc7 Binary files /dev/null and b/version/dev/_images/unitcell.png differ diff --git a/version/dev/_images/user_interface.png b/version/dev/_images/user_interface.png new file mode 100644 index 00000000..2b35e10e Binary files /dev/null and b/version/dev/_images/user_interface.png differ diff --git a/version/dev/_images/virtual_compliance_class.png b/version/dev/_images/virtual_compliance_class.png new file mode 100644 index 00000000..d6c3e6bf Binary files /dev/null and b/version/dev/_images/virtual_compliance_class.png differ diff --git a/version/dev/_images/virtual_compliance_configs.png b/version/dev/_images/virtual_compliance_configs.png new file mode 100644 index 00000000..85f93b21 Binary files /dev/null and b/version/dev/_images/virtual_compliance_configs.png differ diff --git a/version/dev/_images/virtual_compliance_eye.png b/version/dev/_images/virtual_compliance_eye.png new file mode 100644 index 00000000..890d49ff Binary files /dev/null and b/version/dev/_images/virtual_compliance_eye.png differ diff --git a/version/dev/_images/virtual_compliance_scattering1.png b/version/dev/_images/virtual_compliance_scattering1.png new file mode 100644 index 00000000..a78e3dc8 Binary files /dev/null and b/version/dev/_images/virtual_compliance_scattering1.png differ diff --git a/version/dev/_images/virtual_compliance_scattering2.png b/version/dev/_images/virtual_compliance_scattering2.png new file mode 100644 index 00000000..e9afcb68 Binary files /dev/null and b/version/dev/_images/virtual_compliance_scattering2.png differ diff --git a/version/dev/_images/virtual_compliance_usage.png b/version/dev/_images/virtual_compliance_usage.png new file mode 100644 index 00000000..77902600 Binary files /dev/null and b/version/dev/_images/virtual_compliance_usage.png differ diff --git a/version/dev/_images/wgf.png b/version/dev/_images/wgf.png new file mode 100644 index 00000000..0f3d78bf Binary files /dev/null and b/version/dev/_images/wgf.png differ diff --git a/version/dev/_images/wgf1.png b/version/dev/_images/wgf1.png new file mode 100644 index 00000000..0f3d78bf Binary files /dev/null and b/version/dev/_images/wgf1.png differ diff --git a/version/dev/_sources/examples/aedt/circuit/index.rst.txt b/version/dev/_sources/examples/aedt/circuit/index.rst.txt new file mode 100644 index 00000000..3cfeed2a --- /dev/null +++ b/version/dev/_sources/examples/aedt/circuit/index.rst.txt @@ -0,0 +1,122 @@ +Circuit +~~~~~~~ + +These examples use PyAEDT to show Circuit capabilities. + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: ../../aedt_general/modeler/circuit_schematic + :link-type: doc + + .. image:: ../../aedt_general/modeler/_static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Circuit Netlist to Schematic + :padding: 2 2 2 2 + :link: ../../aedt_general/modeler/netlist_to_schematic + :link-type: doc + + .. image:: ../../aedt_general/modeler/_static/netlist.png + :alt: Netlist + :width: 250px + :height: 250px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Automatic report creation + :padding: 2 2 2 2 + :link: ../../aedt_general/report/automatic_report + :link-type: doc + + .. image:: ../../aedt_general/report/_static/automatic_report.png + :alt: Automatic report + :width: 250px + :height: 200px + :align: center + + This example shows how to create reports from a JSON template file. + + .. grid-item-card:: PCIE virtual compliance + :padding: 2 2 2 2 + :link: ../../aedt_general/report/virtual_compliance + :link-type: doc + + .. image:: ../../aedt_general/report/_static/virtual_compliance_eye.png + :alt: Virtual compliance + :width: 250px + :height: 200px + :align: center + + This example shows how to generate a compliance report in PyAEDT using the VirtualCompliance class. + + .. grid-item-card:: Schematic subcircuit management + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/subcircuit + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/subcircuit.png + :alt: Cable + :width: 250px + :height: 200px + :align: center + + This example shows how to add a subcircuit to a circuit design. + It changes the focus within the hierarchy between the child subcircuit and the parent design. + + .. grid-item-card:: AMI Postprocessing + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/ami + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/ami.png + :alt: AMI + :width: 250px + :height: 200px + :align: center + + This example demonstrates advanced postprocessing of AMI simulations. + + .. grid-item-card:: Multi-zone simulation with SIwave + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/multizone + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/multizone.png + :alt: Multizone + :width: 250px + :height: 200px + :align: center + + This example shows how to simulate multiple zones with SIwave. + + .. grid-item-card:: Circuit transient analysis and eye diagram + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/circuit_transient + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/circuit_transient.png + :alt: Circuit transient + :width: 250px + :height: 200px + :align: center + + This example shows how to create a circuit design, run a Nexxim time-domain simulation, and create an eye diagram. + + + .. toctree:: + :hidden: + + ../../aedt_general/modeler/circuit_schematic + ../../aedt_general/modeler/netlist_to_schematic + ../../aedt_general/report/automatic_report + ../../aedt_general/report/virtual_compliance + ../../high_frequency/emc/subcircuit.py + ../../high_frequency/layout/signal_integrity/ami + ../../high_frequency/layout/signal_integrity/multizone + ../../high_frequency/layout/signal_integrity/circuit_transient diff --git a/version/dev/_sources/examples/aedt/emit/index.rst.txt b/version/dev/_sources/examples/aedt/emit/index.rst.txt new file mode 100644 index 00000000..7df0fba4 --- /dev/null +++ b/version/dev/_sources/examples/aedt/emit/index.rst.txt @@ -0,0 +1,82 @@ +EMIT +~~~~ + +These examples use PyAEDT to show EMIT capabilities. + +.. grid:: 2 + + .. grid-item-card:: Antenna + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/interferences/antenna + :link-type: doc + + .. image:: ../../high_frequency/antenna/interferences/_static/emit.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project in EMIT for the simulation of an antenna using HFSS. + + .. grid-item-card:: HFSS to EMIT coupling + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/interferences/hfss_emit + :link-type: doc + + .. image:: ../../high_frequency/antenna/interferences/_static/emit_hfss.png + :alt: EMIT HFSS + :width: 250px + :height: 200px + :align: center + + This example shows how to link an HFSS design to EMIT and model RF interference among various components. + + .. grid-item-card:: Interference type classification + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/interferences/interference + :link-type: doc + + .. image:: ../../high_frequency/antenna/interferences/_static/interference.png + :alt: EMIT HFSS + :width: 250px + :height: 200px + :align: center + + This example shows how to load an existing AEDT EMIT design and analyze the results to classify the worst-case interference. + + .. grid-item-card:: Compute receiver protection levels + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/interferences/interference_type + :link-type: doc + + .. image:: ../../high_frequency/antenna/interferences/_static/protection.png + :alt: EMIT protection + :width: 250px + :height: 200px + :align: center + + This example shows how to open an AEDT project with an EMIT design and analyze the results to determine if + the received power at the input to each receiver exceeds the specified protection levels. + + .. grid-item-card:: Interference type classification using a GUI + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/interferences/interference_type + :link-type: doc + + .. image:: ../../high_frequency/antenna/interferences/_static/interference_type.png + :alt: EMIT protection + :width: 250px + :height: 200px + :align: center + + This example uses a GUI to open an AEDT project with an EMIT design and analyze the results to classify + the worst-case interference. + + .. toctree:: + :hidden: + + ../../high_frequency/antenna/interferences/antenna + ../../high_frequency/antenna/interferences/hfss_emit + ../../high_frequency/antenna/interferences/interference + ../../high_frequency/antenna/interferences/protection + ../../high_frequency/antenna/interferences/interference_type diff --git a/version/dev/_sources/examples/aedt/hfss/index.rst.txt b/version/dev/_sources/examples/aedt/hfss/index.rst.txt new file mode 100644 index 00000000..a2d7d08c --- /dev/null +++ b/version/dev/_sources/examples/aedt/hfss/index.rst.txt @@ -0,0 +1,250 @@ +HFSS +~~~~ + +These examples use PyAEDT to show HFSS capabilities + +.. grid:: 2 + + .. grid-item-card:: Dipole antenna + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/dipole + :link-type: doc + + .. image:: ../../high_frequency/antenna/_static/dipole.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a dipole antenna in HFSS and postprocess results. + + .. grid-item-card:: Component antenna array + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/array + :link-type: doc + + .. image:: ../../high_frequency/antenna/_static/array.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an antenna array. + + .. grid-item-card:: Probe-fed patch antenna + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/patch + :link-type: doc + + .. image:: ../../high_frequency/antenna/_static/patch.png + :alt: Patch + :width: 250px + :height: 200px + :align: center + + This example shows how to use the Stackup3D class to create and analyze a patch antenna in HFSS. + + .. grid-item-card:: FSS unit cell simulation + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/fss_unitcell + :link-type: doc + + .. image:: ../../high_frequency/antenna/_static/unitcell.png + :alt: FSS + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to model and simulate a unit cell for a frequency-selective surface in HFSS. + + .. grid-item-card:: Geometry import from maps + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/large_scenarios/city + :link-type: doc + + .. image:: ../../high_frequency/antenna/large_scenarios/_static/city.png + :alt: City + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an HFSS SBR+ project from OpenStreetMap. + + .. grid-item-card:: Doppler setup + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/large_scenarios/doppler + :link-type: doc + + .. image:: ../../high_frequency/antenna/large_scenarios/_static/doppler.png + :alt: Doppler + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a multipart scenario in HFSS SBR+ and set up a doppler analysis. + + .. grid-item-card:: Reflector + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/large_scenarios/reflector + :link-type: doc + + .. image:: ../../high_frequency/antenna/large_scenarios/_static/reflector.png + :alt: Reflector + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an HFSS SBR+ project from an HFSS antenna and run a simulation. + + .. grid-item-card:: HFSS to SBR+ time animation + :padding: 2 2 2 2 + :link: ../../high_frequency/antenna/large_scenarios/time_domain + :link-type: doc + + .. image:: ../../high_frequency/antenna/large_scenarios/_static/time_domain.png + :alt: SBR Time + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an SBR+ time animation and save it to a GIF file. + + .. grid-item-card:: Choke + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/choke + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/choke.png + :alt: Choke + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a choke setup in HFSS. + + .. grid-item-card:: Eigenmode filter + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/eigenmode + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/eigenmode.png + :alt: Eigenmode + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to automate the Eigenmode solver in HFSS. + + .. grid-item-card:: Flex cable CPWG + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/flex_cable + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/flex_cable.png + :alt: Flex cable + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a flex cable CPWG (coplanar waveguide with ground). + + .. grid-item-card:: HFSS-Mechanical MRI analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/multiphysics/mri + :link-type: doc + + .. image:: ../../high_frequency/multiphysics/_static/mri.png + :alt: MRI + :width: 250px + :height: 200px + :align: center + + This example uses a coil tuned to 63.8 MHz to determine the temperature rise in a gel phantom near + an implant given a background SAR of 1 W/kg. + + .. grid-item-card:: HFSS-Mechanical multiphysics analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/multiphysics/hfss_mechanical + :link-type: doc + + .. image:: ../../high_frequency/multiphysics/_static/hfss_mechanical.png + :alt: HFSS Mechanical + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a multiphysics workflow that includes Circuit, HFSS, and Mechanical. + + .. grid-item-card:: Inductive iris waveguide filter + :padding: 2 2 2 2 + :link: ../../high_frequency/radiofrequency_mmwave/iris_filter + :link-type: doc + + .. image:: ../../high_frequency/radiofrequency_mmwave/_static/wgf.png + :alt: Waveguide filter + :width: 250px + :height: 200px + :align: center + + This example shows how to build and analyze a four-pole X-Band waveguide filter using inductive irises. + + .. grid-item-card:: Spiral inductor + :padding: 2 2 2 2 + :link: ../../high_frequency/radiofrequency_mmwave/spiral + :link-type: doc + + .. image:: ../../high_frequency/radiofrequency_mmwave/_static/spiral.png + :alt: Spiral + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a spiral inductor, solve it, and plot results. + + .. grid-item-card:: Coaxial + :padding: 2 2 2 2 + :link: ../../electrothermal/ccoaxial_hfss_icepak + :link-type: doc + + .. image:: ../../electrothermal/_static/coaxial.png + :alt: Coaxial + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project from scratch in HFSS and Icepak. + + .. grid-item-card:: Circuit-HFSS-Icepak coupling workflow + :padding: 2 2 2 2 + :link: ../../electrothermal/icepak_circuit_hfss_coupling + :link-type: doc + + .. image:: ../../electrothermal/_static/ring.png + :alt: Ring + :width: 250px + :height: 200px + :align: center + + This example shows how to create a two-way coupling between HFSS and Icepak. + + + .. toctree:: + :hidden: + + ../../high_frequency/antenna/array + ../../high_frequency/antenna/dipole + ../../high_frequency/antenna/fss_unitcell + ../../high_frequency/antenna/patch + ../../high_frequency/antenna/large_scenarios/city + ../../high_frequency/antenna/large_scenarios/doppler + ../../high_frequency/antenna/large_scenarios/reflector + ../../high_frequency/antenna/large_scenarios/time_domain + ../../high_frequency/emc/choke + ../../high_frequency/emc/eigenmode + ../../high_frequency/emc/flex_cable.py + ../../high_frequency/multiphysics/hfss_mechanical + ../../high_frequency/multiphysics/mri + ../../high_frequency/radiofrequency_mmwave/iris_filter + ../../high_frequency/radiofrequency_mmwave/spiral + ../../electrothermal/coaxial_hfss_icepak + ../../electrothermal/icepak_circuit_hfss_coupling diff --git a/version/dev/_sources/examples/aedt/hfss_3d_layout/index.rst.txt b/version/dev/_sources/examples/aedt/hfss_3d_layout/index.rst.txt new file mode 100644 index 00000000..e2a02ea0 --- /dev/null +++ b/version/dev/_sources/examples/aedt/hfss_3d_layout/index.rst.txt @@ -0,0 +1,82 @@ +HFSS 3D Layout +~~~~~~~~~~~~~~ + +These examples use PyAEDT to show HFSS 3D Layout capabilities. + +.. grid:: 2 + + .. grid-item-card:: Power integrity analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/power_integrity/power_integrity + :link-type: doc + + .. image:: ../../high_frequency/layout/power_integrity/_static/power_integrity.png + :alt: Power integrity + :width: 250px + :height: 200px + :align: center + + This example shows how to use the Ansys Electronics Database (EDB) for power integrity analysis. + + .. grid-item-card:: DC IR analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/power_integrity/dcir + :link-type: doc + + .. image:: ../../high_frequency/layout/power_integrity/_static/dcir.png + :alt: DCIR + :width: 250px + :height: 200px + :align: center + + This example shows how to configure EDB for DC IR analysis and load EDB into the HFSS 3D Layout UI for analysis + and postprocessing. + + .. grid-item-card:: Pre-layout signal integrity + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/pre_layout + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/pre_layout_sma_connector_on_pcb.png + :alt: Pre layout connector + :width: 250px + :height: 200px + :align: center + + This example shows how to create a parameterized layout design and load the layout into HFSS 3D Layout + for analysis and postprocessing. + + .. grid-item-card:: Pre-layout Parameterized PCB + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/pre_layout_parametrized + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/pre_layout_parameterized_pcb.png + :alt: Pre layout parametrized + :width: 250px + :height: 200px + :align: center + + This example shows how to use the EDB interface along with HFSS 3D Layout to create and solve a parameterized layout. + + .. grid-item-card:: HFSS 3D Layout GUI modificatation + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/gui_manipulation + :link-type: doc + + .. image:: ../../high_frequency/layout/_static/user_interface.png + :alt: UI 3D Layout + :width: 250px + :height: 200px + :align: center + + Provides HFSS 3D Layout GUI modification examples. + + .. toctree:: + :hidden: + + ../../high_frequency/layout/power_integrity/power_integrity + ../../high_frequency/layout/power_integrity/dcir + ../../high_frequency/layout/signal_integrity/pre_layout + ../../high_frequency/layout/signal_integrity/pre_layout_parametrized + ../../high_frequency/layout/gui_manipulation diff --git a/version/dev/_sources/examples/aedt/icepak/index.rst.txt b/version/dev/_sources/examples/aedt/icepak/index.rst.txt new file mode 100644 index 00000000..62dc6a7b --- /dev/null +++ b/version/dev/_sources/examples/aedt/icepak/index.rst.txt @@ -0,0 +1,148 @@ +Icepak +~~~~~~ + +These examples use PyAEDT to show Icepak capabilities. + +.. grid:: 2 + + .. grid-item-card:: PCB component definition from CSV file and model image exports + :padding: 2 2 2 2 + :link: ../../electrothermal/components_csv + :link-type: doc + + .. image:: ../../electrothermal/_static/icepak_csv.png + :alt: Icepak CSV + :width: 250px + :height: 200px + :align: center + + This example shows how to create different types of blocks and assign power and material to them using a CSV input file. + + + .. grid-item-card:: Import of a PCB and its components via IDF and EDB + :padding: 2 2 2 2 + :link: ../../electrothermal/ecad_import + :link-type: doc + + .. image:: ../../electrothermal/_static/ecad.png + :alt: Icepak ECAD + :width: 250px + :height: 200px + :align: center + + This example shows how to import a PCB and its components using IDF files (LDB and BDF). + You can also use a combination of EMN and EMP files in a similar way. + + + .. grid-item-card:: Thermal analysis with 3D components + :padding: 2 2 2 2 + :link: ../../electrothermal/component_3d + :link-type: doc + + .. image:: ../../electrothermal/_static/component.png + :alt: Thermal component + :width: 250px + :height: 200px + :align: center + + This example shows how to create a thermal analysis of an electronic package by taking advantage of 3D components with advanced features added by PyAEDT. + + + .. grid-item-card:: Graphic card thermal analysis + :padding: 2 2 2 2 + :link: ../../electrothermal/graphic_card + :link-type: doc + + .. image:: ../../electrothermal/_static/graphic.png + :alt: Graphic card + :width: 250px + :height: 200px + :align: center + + This example shows how to use pyAEDT to create a graphic card setup in Icepak and postprocess the results. + The example file is an Icepak project with a model that is already created and has materials assigned. + + + .. grid-item-card:: Coaxial + :padding: 2 2 2 2 + :link: ../../electrothermal/coaxial_hfss_icepak + :link-type: doc + + .. image:: ../../electrothermal/_static/coaxial.png + :alt: Coaxial + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project from scratch in HFSS and Icepak. + + + .. grid-item-card:: Setup from Sherlock inputs + :padding: 2 2 2 2 + :link: ../../electrothermal/sherlock + :link-type: doc + + .. image:: ../../electrothermal/_static/sherlock.png + :alt: PyAEDT logo + :width: 250px + :height: 200px + :align: center + + This example shows how to create an Icepak project from Sherlock files (STEP and CSV) and an AEDB board. + + .. grid-item-card:: Circuit-HFSS-Icepak coupling workflow + :padding: 2 2 2 2 + :link: ../../electrothermal/icepak_circuit_hfss_coupling + :link-type: doc + + .. image:: ../../electrothermal/_static/ring.png + :alt: Ring + :width: 250px + :height: 200px + :align: center + + This example shows how to create a two-way coupling between HFSS and Icepak. + + + .. grid-item-card:: Electrothermal analysis + :padding: 2 2 2 2 + :link: ../../electrothermal/electrothermal + :link-type: doc + + .. image:: ../../electrothermal/_static/electrothermal.png + :alt: Electrothermal + :width: 250px + :height: 200px + :align: center + + This example shows how to use the EDB for DC IR analysis and electrothermal analysis. + The EDB is loaded into SIwave for analysis and postprocessing. + In the end, an Icepak project is exported from SIwave. + + + .. grid-item-card:: Maxwell 3D-Icepak electrothermal analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/multiphysics/maxwell_icepak + :link-type: doc + + .. image:: ../../low_frequency/multiphysics/_static/charging.png + :alt: Charging + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a simple Maxwell design consisting of a coil and a ferrite core. + + + .. toctree:: + :hidden: + + ../../electrothermal/components_csv + ../../electrothermal/ecad_import + ../../electrothermal/component_3d + ../../electrothermal/graphic_card + ../../electrothermal/coaxial_hfss_icepak + ../../electrothermal/sherlock + ../../electrothermal/icepak_circuit_hfss_coupling + ../../electrothermal/electrothermal + ../../low_frequency/multiphysics/maxwell_icepak diff --git a/version/dev/_sources/examples/aedt/index.rst.txt b/version/dev/_sources/examples/aedt/index.rst.txt new file mode 100644 index 00000000..e749e04f --- /dev/null +++ b/version/dev/_sources/examples/aedt/index.rst.txt @@ -0,0 +1,77 @@ +Examples by AEDT application +============================ + +These examples are groped by AEDT applications. + + +.. grid:: 2 + + .. grid-item-card:: HFSS + :padding: 2 2 2 2 + :link: hfss/index + :link-type: doc + + HFSS examples + + .. grid-item-card:: Maxwell 3D + :padding: 2 2 2 2 + :link: maxwell_3d/index + :link-type: doc + + Maxwell 3D examples + + .. grid-item-card:: Maxwell 2D + :padding: 2 2 2 2 + :link: maxwell_2d/index + :link-type: doc + + Maxwell 2D examples + + .. grid-item-card:: Icepak + :padding: 2 2 2 2 + :link: icepak/index + :link-type: doc + + Icepak examples + + .. grid-item-card:: HFSS 3D Layout + :padding: 2 2 2 2 + :link: hfss_3d_layout/index + :link-type: doc + + HFSS 3D Layout examples + + .. grid-item-card:: Q3D and 2D Extractor + :padding: 2 2 2 2 + :link: q3d_q2d/index + :link-type: doc + + Q3D and 2D Extractor examples + + .. grid-item-card:: Circuit + :padding: 2 2 2 2 + :link: circuit/index + :link-type: doc + + Circuit examples + + .. grid-item-card:: EMIT + :padding: 2 2 2 2 + :link: emit/index + :link-type: doc + + EMIT examples + + .. grid-item-card:: Twin Builder + :padding: 2 2 2 2 + :link: twin_builder/index + :link-type: doc + + Twin Builder examples + + .. grid-item-card:: Miscellaneous + :padding: 2 2 2 2 + :link: misc/index + :link-type: doc + + Miscellaneous examples \ No newline at end of file diff --git a/version/dev/_sources/examples/aedt/maxwell_2d/index.rst.txt b/version/dev/_sources/examples/aedt/maxwell_2d/index.rst.txt new file mode 100644 index 00000000..500a507b --- /dev/null +++ b/version/dev/_sources/examples/aedt/maxwell_2d/index.rst.txt @@ -0,0 +1,167 @@ +Maxwell 2D +~~~~~~~~~~ + +These examples use PyAEDT to show Maxwell 2D capabilities. + +.. grid:: 2 + + .. grid-item-card:: Control program enablement + :padding: 2 2 2 2 + :link: ../../low_frequency/general/control_program + :link-type: doc + + .. image:: ../../low_frequency/general/_static/control_program.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to enable a control program in a Maxwell 2D project. + + .. grid-item-card:: Resistance calculation + :padding: 2 2 2 2 + :link: ../../low_frequency/general/resistance + :link-type: doc + + .. image:: ../../low_frequency/general/_static/resistance.png + :alt: Maxwell resistance + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a resistance calculation and solve it using the Maxwell 2D DCConduction solver. + + + .. grid-item-card:: Eddy current analysis and reduced matrix + :padding: 2 2 2 2 + :link: ../../low_frequency/general/eddy_current + :link-type: doc + + .. image:: ../../low_frequency/general/_static/eddy_current.png + :alt: Maxwell Eddy current + :width: 250px + :height: 200px + :align: center + + This example shows how to leverage PyAEDT to assign a matrix and perform series or parallel connections in a Maxwell 2D design. + + + .. grid-item-card:: Electrostatic analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/general/electrostatic + :link-type: doc + + .. image:: ../../low_frequency/general/_static/electrostatic.png + :alt: Maxwell electrostatic + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D electrostatic analysis. + + + .. grid-item-card:: External delta circuit + :padding: 2 2 2 2 + :link: ../../low_frequency/general/external_circuit + :link-type: doc + + .. image:: ../../low_frequency/general/_static/external_circuit.png + :alt: External circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to create an external delta circuit and connect it with a Maxwell 2D design. + + .. grid-item-card:: Magnetomotive force + :padding: 2 2 2 2 + :link: ../../low_frequency/magnetic/magneto_motive_line + :link-type: doc + + .. image:: ../../low_frequency/magnetic/_static/magneto.png + :alt: Maxwell magneto force + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to calculate the magnetomotive force. + + .. grid-item-card:: Transient winding analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/magnetic/transient_winding + :link-type: doc + + .. image:: ../../low_frequency/magnetic/_static/transient.png + :alt: Maxwell transient + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a project in Maxwell 2D and run a transient simulation. + + .. grid-item-card:: Lorentz actuator + :padding: 2 2 2 2 + :link: ../../low_frequency/magnetic/lorentz_actuator + :link-type: doc + + .. image:: ../../low_frequency/magnetic/_static/lorentz_actuator.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a Lorentz actuator and solve it using the Maxwell 2D transient solver. + + .. grid-item-card:: PM synchronous motor transient analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/motor/aedt_motor/pm_synchronous + :link-type: doc + + .. image:: ../../low_frequency/motor/aedt_motor/_static/pm_synchronous.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D transient analysis for an interior permanent magnet (PM) electric motor. + + .. grid-item-card:: Motor creation and export + :padding: 2 2 2 2 + :link: ../../low_frequency/motor/aedt_motor/rmxpert + :link-type: doc + + .. image:: ../../low_frequency/motor/aedt_motor/_static/rmxpert.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to create a RMxprt project and export it to Maxwell 2D. + + .. grid-item-card:: Transformer leakage inductance calculation + :padding: 2 2 2 2 + :link: ../../low_frequency/motor/aedt_motor/transformer_inductance + :link-type: doc + + .. image:: ../../low_frequency/motor/aedt_motor/_static/transformer2.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D magnetostatic analysis to calculate transformer leakage inductance and reactance. + + .. toctree:: + :hidden: + + ../../low_frequency/general/control_program + ../../low_frequency/general/resistance + ../../low_frequency/general/eddy_current + ../../low_frequency/general/electrostatic + ../../low_frequency/general/external_circuit + ../../low_frequency/magnetic/magneto_motive_line + ../../low_frequency/magnetic/transient_winding + ../../low_frequency/magnetic/lorentz_actuator + ../../low_frequency/motor/aedt_motor/pm_synchronous + ../../low_frequency/motor/aedt_motor/rmxpert + ../../low_frequency/motor/aedt_motor/transformer_inductance diff --git a/version/dev/_sources/examples/aedt/maxwell_3d/index.rst.txt b/version/dev/_sources/examples/aedt/maxwell_3d/index.rst.txt new file mode 100644 index 00000000..c0bda9fa --- /dev/null +++ b/version/dev/_sources/examples/aedt/maxwell_3d/index.rst.txt @@ -0,0 +1,126 @@ +Maxwell 3D +~~~~~~~~~~ + +These examples use PyAEDT to show Maxwell 3D capabilities. + +.. grid:: 2 + + .. grid-item-card:: Electro DC analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/general/dc_analysis + :link-type: doc + + .. image:: ../../low_frequency/general/_static/dc.png + :alt: Maxwell DC + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell DC analysis, compute mass center, and move coordinate systems. + + + .. grid-item-card:: Fields export in transient analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/general/field_export + :link-type: doc + + .. image:: ../../low_frequency/general/_static/field.png + :alt: Maxwell field + :width: 250px + :height: 200px + :align: center + + This example shows how to leverage PyAEDT to set up a Maxwell 3D transient analysis and then + compute the average value of the current density field over a specific coil surface and the magnitude + of the current density field over all coil surfaces at each time step of the transient analysis. + + .. grid-item-card:: Choke setup + :padding: 2 2 2 2 + :link: ../../low_frequency/magnetic/choke + :link-type: doc + + .. image:: ../../low_frequency/magnetic/_static/choke.png + :alt: Maxwell choke + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a choke setup in Maxwell 3D. + + .. grid-item-card:: Magnet segmentation + :padding: 2 2 2 2 + :link: ../../low_frequency/motor/aedt_motor/magnet_segmentation + :link-type: doc + + .. image:: ../../low_frequency/motor/aedt_motor/_static/magnet_segmentation.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to segment magnets of an electric motor. The method is valid and usable for any object you would like to segment. + + .. grid-item-card:: Transformer + :padding: 2 2 2 2 + :link: ../../low_frequency/motor/aedt_motor/transformer + :link-type: doc + + .. image:: ../../low_frequency/motor/aedt_motor/_static/transformer.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to set core loss given a set of power-volume [kw/m^3] curves at different frequencies. + + .. grid-item-card:: Maxwell 3D-Icepak electrothermal analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/multiphysics/maxwell_icepak + :link-type: doc + + .. image:: ../../low_frequency/multiphysics/_static/charging.png + :alt: Charging + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a simple Maxwell design consisting of a coil and a ferrite core. + + .. grid-item-card:: Asymmetric conductor analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/team_problem/asymmetric_conductor + :link-type: doc + + .. image:: ../../low_frequency/team_problem/_static/asymmetric_conductor.png + :alt: Asymmetric conductor + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up the TEAM 7 problem for an asymmetric conductor with a hole and solve it using the Maxwell 3D eddy current solver. + + .. grid-item-card:: Bath plate analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/team_problem/bath_plate + :link-type: doc + + .. image:: ../../low_frequency/team_problem/_static/bath.png + :alt: Bath + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up the TEAM 3 bath plate problem and solve it using the Maxwell 3D eddy current solver. + + + .. toctree:: + :hidden: + + ../../low_frequency/general/dc_analysis + ../../low_frequency/general/field_export + ../../low_frequency/magnetic/choke + ../../low_frequency/motor/aedt_motor/magnet_segmentation + ../../low_frequency/motor/aedt_motor/transformer + ../../low_frequency/multiphysics/maxwell_icepak + ../../low_frequency/team_problem/asymmetric_conductor + ../../low_frequency/team_problem/bath_plate diff --git a/version/dev/_sources/examples/aedt/misc/index.rst.txt b/version/dev/_sources/examples/aedt/misc/index.rst.txt new file mode 100644 index 00000000..33c95bc0 --- /dev/null +++ b/version/dev/_sources/examples/aedt/misc/index.rst.txt @@ -0,0 +1,53 @@ +Miscellaneous +~~~~~~~~~~~~~ + +These examples use PyAEDT to show miscellaneous capabilities. + +.. grid:: 2 + + .. grid-item-card:: Touchstone files + :padding: 2 2 2 2 + :link: ../../aedt_general/report/touchstone_file + :link-type: doc + + .. image:: ../../aedt_general/report/_static/touchstone_skitrf.png + :alt: Touchstone file + :width: 250px + :height: 200px + :align: center + + This example shows how to use objects in a Touchstone file without opening AEDT. + + .. grid-item-card:: Channel Operating Margin (COM) + :padding: 2 2 2 2 + :link: ../../high_frequency/layout/signal_integrity/com_analysis + :link-type: doc + + .. image:: ../../high_frequency/layout/signal_integrity/_static/com_eye.png + :alt: COM + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT for COM analysis. + + .. grid-item-card:: Lumped element filter design + :padding: 2 2 2 2 + :link: ../../high_frequency/radiofrequency_mmwave/lumped_element + :link-type: doc + + .. image:: ../../high_frequency/radiofrequency_mmwave/_static/lumped_filter.png + :alt: Stripline + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to use the FilterSolutions module to design and visualize the frequency + response of a band-pass Butterworth filter. + + .. toctree:: + :hidden: + + ../../aedt_general/report/touchstone_file + ../../high_frequency/layout/signal_integrity/com_analysis + ../../high_frequency/radiofrequency_mmwave/lumped_element diff --git a/version/dev/_sources/examples/aedt/q3d_q2d/index.rst.txt b/version/dev/_sources/examples/aedt/q3d_q2d/index.rst.txt new file mode 100644 index 00000000..7358fe5c --- /dev/null +++ b/version/dev/_sources/examples/aedt/q3d_q2d/index.rst.txt @@ -0,0 +1,99 @@ +Q2D-Q3D +~~~~~~~ + +These examples use PyAEDT to show Q3D and 2D Extractor capabilities. + +.. grid:: 2 + + .. grid-item-card:: Cable parameter identification + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/armoured_cable + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/armoured.png + :alt: Cable + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create see a 4 Core Armoured Power Cable. + + .. grid-item-card:: Busbar analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/emc/busbar + :link-type: doc + + .. image:: ../../high_frequency/emc/_static/busbar.png + :alt: Busbar + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a busbar design in Q3D Extractor and run a simulation. + + .. grid-item-card:: PCB DCIR analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/layout//power_integrity/dcir_q3d + :link-type: doc + + .. image:: ../../high_frequency/layout//power_integrity/_static/dcir_q3d.png + :alt: DCIR + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a design in Q3D Extractor and run a DC IR drop simulation starting + from an EDB project. + + .. grid-item-card:: PCB AC analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/layout//power_integrity/ac_q3d + :link-type: doc + + .. image:: ../../high_frequency/layout//power_integrity/_static/ac_q3d.png + :alt: AC Q3D + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a design in Q3D Extractor and run a simulation starting + from an EDB project. + + .. grid-item-card:: CPWG analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/radiofrequency_mmwave/coplanar_waveguide + :link-type: doc + + .. image:: ../../high_frequency/radiofrequency_mmwave/_static/cpwg.png + :alt: CPWG + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a CPWG (coplanar waveguide with ground) design in 2D Extractor and run a simulation. + + .. grid-item-card:: Stripline analysis + :padding: 2 2 2 2 + :link: ../../high_frequency/radiofrequency_mmwave/stripline + :link-type: doc + + .. image:: ../../high_frequency/radiofrequency_mmwave/_static/stripline.png + :alt: Stripline + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a differential stripline design in 2D Extractor and run a simulation. + + + .. toctree:: + :hidden: + + ../../high_frequency/emc/armoured_cable + ../../high_frequency/emc/busbar + ../../high_frequency/layout//power_integrity/dcir_q3d + ../../high_frequency/layout/power_integrity/ac_q3d + ../../high_frequency/radiofrequency_mmwave/coplanar_waveguide + ../../high_frequency/radiofrequency_mmwave/stripline + + diff --git a/version/dev/_sources/examples/aedt/twin_builder/index.rst.txt b/version/dev/_sources/examples/aedt/twin_builder/index.rst.txt new file mode 100644 index 00000000..ba688e95 --- /dev/null +++ b/version/dev/_sources/examples/aedt/twin_builder/index.rst.txt @@ -0,0 +1,82 @@ +Twin Builder +~~~~~~~~~~~~ + +These examples use PyAEDT to show Twin Builder capabilities. + +.. grid:: 2 + + .. grid-item-card:: RC circuit design analysis + :padding: 2 2 2 2 + :link: ../../low_frequency/general/twin_builder/rc_circuit + :link-type: doc + + .. image:: ../../low_frequency/general/twin_builder/_static/rc.png + :alt: TB RC + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Twin Builder design and run a Twin Builder time-domain simulation. + + .. grid-item-card:: Wiring of a rectifier with a capacitor filter + :padding: 2 2 2 2 + :link: ../../low_frequency/general/twin_builder/rectifier + :link-type: doc + + .. image:: ../../low_frequency/general/twin_builder/_static/rectifier_response.png + :alt: TB Rectifier response + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Twin Builder design and run a Twin Builder time-domain simulation. + + + .. grid-item-card:: Static ROM + :padding: 2 2 2 2 + :link: ../../low_frequency/general/twin_builder/static_rom + :link-type: doc + + .. image:: ../../low_frequency/general/twin_builder/_static/static_rom.png + :alt: Static ROM + :width: 250px + :height: 200px + :align: center + + This example shows how to create a static reduced order model (ROM) in Twin Builder and run a transient simulation. + + .. grid-item-card:: Dynamic ROM + :padding: 2 2 2 2 + :link: ../../low_frequency/general/twin_builder/dynamic_rom + :link-type: doc + + .. image:: ../../low_frequency/general/twin_builder/_static/dynamic_rom_plot.png + :alt: Dynamic ROM plot + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a dynamic reduced order model (ROM) in Twin Builder and run a Twin Builder time-domain simulation. + + .. grid-item-card:: LTI ROM + :padding: 2 2 2 2 + :link: ../../low_frequency/general/twin_builder/lti_rom_sml + :link-type: doc + + .. image:: ../../low_frequency/general/twin_builder/_static/lti_rom.png + :alt: LTI ROM plot + :width: 250px + :height: 200px + :align: center + + This example shows how you can use PyAEDT to create a Linear Time Invariant (LTI) ROM in Twin Builder + and run a Twin Builder time-domain simulation. + + .. toctree:: + :hidden: + + ../../low_frequency/general/twin_builder/dynamic_rom + ../../low_frequency/general/twin_builder/rc_circuit + ../../low_frequency/general/twin_builder/rectifier + ../../low_frequency/general/twin_builder/static_rom + ../../low_frequency/general/twin_builder/lti_rom_sml \ No newline at end of file diff --git a/version/dev/_sources/examples/aedt_general/components/component_conversion.ipynb.txt b/version/dev/_sources/examples/aedt_general/components/component_conversion.ipynb.txt new file mode 100644 index 00000000..aebe7191 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/components/component_conversion.ipynb.txt @@ -0,0 +1,356 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6077f52e", + "metadata": {}, + "source": [ + "# Encrypted 3D component conversion\n", + "\n", + "This example shows how to convert an encrypted\n", + "3D component from ACIS to Parasolid in different AEDT releases.\n", + "If you have models previous to Ansys AEDT 2023 R1 with an ACIS kernel,\n", + "you can convert it to Parasolid.\n", + "\n", + "Keywords: **HFSS**, **Encrypted**, **3D component**, **Modeler kernel**." + ] + }, + { + "cell_type": "markdown", + "id": "72c51a93", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "aec488c7", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Import the required packages.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98db6af5", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a3041c7", + "metadata": {}, + "outputs": [], + "source": [ + "from pyaedt import Desktop, Hfss, settings\n", + "from pyedb.misc.downloads import download_file" + ] + }, + { + "cell_type": "markdown", + "id": "949e71d5", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb74e11d", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "OLD_AEDT_VERSION = \"2024.1\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "3b3d2fb4", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91384f44", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "3e2ab699", + "metadata": {}, + "source": [ + "## Download encrypted example\n", + "\n", + "Download the encrypted 3D component example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fe68aa7", + "metadata": {}, + "outputs": [], + "source": [ + "a3dcomp = download_file(\n", + " directory=\"component_3d\",\n", + " filename=\"SMA_Edge_Connector_23r2_encrypted_password_ansys.a3dcomp\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9d7e98c6", + "metadata": {}, + "source": [ + "## Enable multiple desktop support" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c02d89e6", + "metadata": {}, + "outputs": [], + "source": [ + "settings.use_multi_desktop = True" + ] + }, + { + "cell_type": "markdown", + "id": "171b44b6", + "metadata": {}, + "source": [ + "## Prepare encrypted 3D component in ACIS\n", + "\n", + "Launch the old AEDT release." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07782c4e", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_old = Desktop(new_desktop=True, version=OLD_AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "5a18c61b", + "metadata": {}, + "source": [ + "Insert an empty HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3c86f36", + "metadata": {}, + "outputs": [], + "source": [ + "hfss1 = Hfss(aedt_process_id=aedt_old.aedt_process_id, solution_type=\"Terminal\")" + ] + }, + { + "cell_type": "markdown", + "id": "5b1cde78", + "metadata": {}, + "source": [ + "Insert the encrypted 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43008519", + "metadata": {}, + "outputs": [], + "source": [ + "cmp = hfss1.modeler.insert_3d_component(comp_file=a3dcomp, password=\"ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "455a7511", + "metadata": {}, + "source": [ + "Open the 3D component in an HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "395d8905", + "metadata": {}, + "outputs": [], + "source": [ + "app_comp = cmp.edit_definition(password=\"ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "5012ae62", + "metadata": {}, + "source": [ + "## Create an encrypted 3D component in Parasolid\n", + "\n", + "Launch the new AEDT release" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d60132b1", + "metadata": {}, + "outputs": [], + "source": [ + "aedt = Desktop(new_desktop_session=True, specified_version=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "5f2c7dbb", + "metadata": {}, + "source": [ + "Insert an empty HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3de58a2d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2 = Hfss(aedt_process_id=aedt.aedt_process_id, solution_type=\"Terminal\")" + ] + }, + { + "cell_type": "markdown", + "id": "4dcd2267", + "metadata": {}, + "source": [ + "Copy objects from the old design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9f36acd", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.copy_solid_bodies_from(design=app_comp, no_vacuum=False, no_pec=False)" + ] + }, + { + "cell_type": "markdown", + "id": "d78d5864", + "metadata": {}, + "source": [ + "Create the new encrypted 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce8d02ba", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.create_3dcomponent(\n", + " input_file=os.path.join(temp_folder.name, r\"SMA_Edge_Connector_encrypted.a3dcomp\"),\n", + " is_encrypted=True,\n", + " edit_password=\"ansys\",\n", + " hide_contents=False,\n", + " allow_edit=True,\n", + " password_type=\"InternalPassword\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6bd4eafa", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6bf97714", + "metadata": {}, + "outputs": [], + "source": [ + "aedt.save_project()\n", + "aedt_old.save_project()\n", + "aedt.release_desktop()\n", + "aedt_old.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1342c643", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6771cbeb", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/components/index.rst.txt b/version/dev/_sources/examples/aedt_general/components/index.rst.txt new file mode 100644 index 00000000..e4c9a142 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/components/index.rst.txt @@ -0,0 +1,38 @@ +3D components +~~~~~~~~~~~~~ + +These examples use PyAEDT to show some 3D component capabilities. + +.. grid:: 2 + + .. grid-item-card:: 3D component creation and reuse + :padding: 2 2 2 2 + :link: reuse_component + :link-type: doc + + .. image:: _static/component_3d.png + :alt: Component creation + :width: 250px + :height: 200px + :align: center + + This example shows how to create and use 3D components. + + .. grid-item-card:: Encrypted 3D component conversion + :padding: 2 2 2 2 + :link: component_conversion + :link-type: doc + + .. image:: _static/e3dcomp.png + :alt: Connector component + :width: 250px + :height: 200px + :align: center + + This example shows how to convert an encrypted 3D component from ACIS to Parasolid in different AEDT releases. + +.. toctree:: + :hidden: + + reuse_component + component_conversion diff --git a/version/dev/_sources/examples/aedt_general/components/reuse_component.ipynb.txt b/version/dev/_sources/examples/aedt_general/components/reuse_component.ipynb.txt new file mode 100644 index 00000000..710a401d --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/components/reuse_component.ipynb.txt @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0d5c46a8", + "metadata": {}, + "source": [ + "# 3D component creation and reuse" + ] + }, + { + "cell_type": "markdown", + "id": "2e0c541c", + "metadata": {}, + "source": [ + "Here is a workflow for creating a 3D component and reusing it:\n", + "\n", + "Step 1: Create an antenna using PyAEDT and HFSS 3D Modeler. (The antenna can also be created using EDB and\n", + "HFSS 3D Layout).\n", + "\n", + "Step 2. Store the object as a 3D component on the disk.\n", + "\n", + "Step 3. Reuse the 3D component in another project.\n", + "\n", + "Step 4. Parametrize and optimize the target design.\n", + "\n", + "Keywords: **AEDT**, **General**, **3D component**." + ] + }, + { + "cell_type": "markdown", + "id": "bbbcd9ba", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb3ce3fe", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95f11504", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Hfss" + ] + }, + { + "cell_type": "markdown", + "id": "01609323", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd5d8ee9", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "fd89b122", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f801086a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "f8c29016", + "metadata": {}, + "source": [ + "Create an HFSS object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6bff377a", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = Hfss(\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " close_on_exit=True,\n", + " non_graphical=NG_MODE,\n", + " solution_type=\"Modal\",\n", + ")\n", + "hfss.save_project(os.path.join(temp_folder.name, \"example.aedt\"))" + ] + }, + { + "cell_type": "markdown", + "id": "7722a93f", + "metadata": {}, + "source": [ + "## Define variables\n", + "\n", + "PyAEDT can create and store all variables available in AEDT (such as design, project,\n", + "and postprocessing)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c83454b", + "metadata": {}, + "outputs": [], + "source": [ + "hfss[\"thick\"] = \"0.1mm\"\n", + "hfss[\"width\"] = \"1mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "d2a9f0bc", + "metadata": {}, + "source": [ + "## Create modeler objects\n", + "\n", + "PyAEDT supports all modeler functionalities available in AEDT.\n", + "You can create, delete, and modify objects using all available Boolean operations.\n", + "PyAEDT can also fully access history." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b939697", + "metadata": {}, + "outputs": [], + "source": [ + "substrate = hfss.modeler.create_box(\n", + " [\"-width\", \"-width\", \"-thick\"],\n", + " [\"2*width\", \"2*width\", \"thick\"],\n", + " material=\"FR4_epoxy\",\n", + " name=\"sub\",\n", + ")\n", + "\n", + "patch = hfss.modeler.create_rectangle(\n", + " \"XY\", [\"-width/2\", \"-width/2\", \"0mm\"], [\"width\", \"width\"], name=\"patch1\"\n", + ")\n", + "\n", + "via1 = hfss.modeler.create_cylinder(\n", + " 2,\n", + " [\"-width/8\", \"-width/4\", \"-thick\"],\n", + " \"0.01mm\",\n", + " \"thick\",\n", + " material=\"copper\",\n", + " name=\"via_inner\",\n", + ")\n", + "\n", + "via_outer = hfss.modeler.create_cylinder(\n", + " 2,\n", + " [\"-width/8\", \"-width/4\", \"-thick\"],\n", + " \"0.025mm\",\n", + " \"thick\",\n", + " material=\"Teflon_based\",\n", + " name=\"via_teflon\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6344c503", + "metadata": {}, + "source": [ + "## Assign bundaries\n", + "\n", + "Most of HFSS boundaries and excitations are already available in PyAEDT.\n", + "You can easily assign a boundary to a face or to an object by taking advantage of\n", + "Object-Oriented Programming (OOP) available in PyAEDT." + ] + }, + { + "cell_type": "markdown", + "id": "8f761014", + "metadata": {}, + "source": [ + "### Assign Perfect E boundary to sheets\n", + "\n", + "Assign a Perfect E boundary to sheets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3cb52b0", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.assign_perfecte_to_sheets(patch)" + ] + }, + { + "cell_type": "markdown", + "id": "a7e400a8", + "metadata": {}, + "source": [ + "### Assign boundaries to faces\n", + "\n", + "Assign boundaries to the top and bottom faces of an object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5cadb75", + "metadata": {}, + "outputs": [], + "source": [ + "side_face = [\n", + " i\n", + " for i in via_outer.faces\n", + " if i.id not in [via_outer.top_face_z.id, via_outer.bottom_face_z.id]\n", + "]\n", + "\n", + "hfss.assign_perfecte_to_sheets(side_face)\n", + "hfss.assign_perfecte_to_sheets(substrate.bottom_face_z)" + ] + }, + { + "cell_type": "markdown", + "id": "d9a95d89", + "metadata": {}, + "source": [ + "## Create wave port\n", + "\n", + "You can assign a wave port to a sheet or to a face of an object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "235f285e", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.wave_port(\n", + " via_outer.bottom_face_z,\n", + " name=\"P1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ecd86495", + "metadata": {}, + "source": [ + "## Create 3D component\n", + "\n", + "Once the model is ready, you can create a 3D component.\n", + "Multiple options are available to partially select objects, coordinate systems,\n", + "boundaries, and mesh operations. You can also create encrypted 3D components." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2339e48d", + "metadata": {}, + "outputs": [], + "source": [ + "component_path = os.path.join(temp_folder.name, \"component_test.aedbcomp\")\n", + "hfss.modeler.create_3dcomponent(component_path, \"patch_antenna\")" + ] + }, + { + "cell_type": "markdown", + "id": "d1503298", + "metadata": {}, + "source": [ + "## Manage multiple project\n", + "\n", + "PyAEDT lets you control multiple projects, designs, and solution types at the same time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94108fff", + "metadata": {}, + "outputs": [], + "source": [ + "new_project = os.path.join(temp_folder.name, \"new_project.aedt\")\n", + "hfss2 = Hfss(\n", + " version=AEDT_VERSION,\n", + " project=new_project,\n", + " design=\"new_design\",\n", + " solution_type=\"Modal\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "126d9141", + "metadata": {}, + "source": [ + "## Insert 3D component\n", + "\n", + "You can insert a 3D component without supplying additional information.\n", + "All needed information is read from the file itself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "970b25f8", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.insert_3d_component(component_path)" + ] + }, + { + "cell_type": "markdown", + "id": "f07384f3", + "metadata": {}, + "source": [ + "## Parametrize 3D components\n", + "\n", + "You can specify parameters for any 3D components." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3706e2bc", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.user_defined_components[\"patch_antenna1\"].parameters\n", + "hfss2[\"p_thick\"] = \"1mm\"\n", + "hfss2.modeler.user_defined_components[\"patch_antenna1\"].parameters[\"thick\"] = \"p_thick\"" + ] + }, + { + "cell_type": "markdown", + "id": "25fd2c60", + "metadata": {}, + "source": [ + "## Insert multiple 3D components\n", + "\n", + "There is no limit to the number of 3D components that can be inserted in a design.\n", + "These components can be the same or linked to different files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "caa06ad7", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.create_coordinate_system(origin=[20, 20, 10], name=\"Second_antenna\")\n", + "ant2 = hfss2.modeler.insert_3d_component(\n", + " component_path, coordinate_system=\"Second_antenna\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b91c30a1", + "metadata": {}, + "source": [ + "## Move 3D components\n", + "\n", + "Move a 3D component by either changing its position or moving the relative coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2bf0abc8", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.coordinate_systems[0].origin = [10, 10, 3]" + ] + }, + { + "cell_type": "markdown", + "id": "a0164a9e", + "metadata": {}, + "source": [ + "## Create air region\n", + "\n", + "Create an air region and assign a boundary to a face or an object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a16925a2", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.create_air_region(30, 30, 30, 30, 30, 30)\n", + "hfss2.assign_radiation_boundary_to_faces(hfss2.modeler[\"Region\"].faces)" + ] + }, + { + "cell_type": "markdown", + "id": "fd8bb87e", + "metadata": {}, + "source": [ + "## Create setup and optimetrics analysis\n", + "\n", + "Once a project is ready to be solved, use PyAEDT to create a setup and parametrics analysis.\n", + "All setup parameters can be edited." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b0b1753", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = hfss2.create_setup()\n", + "optim = hfss2.parametrics.add(\"p_thick\", \"0.2mm\", \"1.5mm\", step=14)" + ] + }, + { + "cell_type": "markdown", + "id": "d91a7b23", + "metadata": {}, + "source": [ + "## Plot objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afaeee1f", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.modeler.fit_all()\n", + "hfss2.plot(\n", + " show=False,\n", + " output_file=os.path.join(hfss.working_directory, \"Image.jpg\"),\n", + " plot_air_objects=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "60d6107b", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d944991", + "metadata": {}, + "outputs": [], + "source": [ + "hfss2.save_project()\n", + "hfss2.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "24d764de", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b67963b9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/configuration_files.ipynb.txt b/version/dev/_sources/examples/aedt_general/configuration_files.ipynb.txt new file mode 100644 index 00000000..d5710c56 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/configuration_files.ipynb.txt @@ -0,0 +1,367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "784857ea", + "metadata": {}, + "source": [ + "# Configuration files\n", + "\n", + "This example shows how to use PyAEDT to export configuration files and reuse\n", + "them to import in a new project. A configuration file is supported by these applications:\n", + "\n", + "* HFSS\n", + "* 2D Extractor and Q3D Extractor\n", + "* Maxwell\n", + "* Icepak (in AEDT)\n", + "* Mechanical (in AEDT)\n", + "\n", + "The following topics are covered:\n", + "\n", + "* Variables\n", + "* Mesh operations (except Icepak)\n", + "* Setup and optimetrics\n", + "* Material properties\n", + "* Object properties\n", + "* Boundaries and excitations\n", + "\n", + "When a boundary is attached to a face, PyAEDT tries to match it with a\n", + "``FaceByPosition`` on the same object name on the target design. If for\n", + "any reason this face position has changed or the object name in the target\n", + "design has changed, the boundary fails to apply.\n", + "\n", + "Keywords: **AEDT**, **general**, **configuration file**, **setup**." + ] + }, + { + "cell_type": "markdown", + "id": "a1107be0", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1d1c313", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "1cb0679c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "787dc8bf", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "0d01ed19", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create the temporary directory.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6a41c22", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "be59ec4a", + "metadata": {}, + "source": [ + "## Download project\n", + "\n", + "Download the Icepack project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7a0c130", + "metadata": {}, + "outputs": [], + "source": [ + "project_full_name = ansys.aedt.core.downloads.download_icepak(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8d785734", + "metadata": {}, + "source": [ + "## Open project\n", + "\n", + "Open the Icepak project from the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "628be7d2", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = ansys.aedt.core.Icepak(\n", + " project=project_full_name,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")\n", + "ipk.autosave_disable()" + ] + }, + { + "cell_type": "markdown", + "id": "b6a4caa7", + "metadata": {}, + "source": [ + "## Create source blocks\n", + "\n", + "Create a source block on the CPU and memories." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b10761b4", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.create_source_block(object_name=\"CPU\", input_power=\"25W\")\n", + "ipk.create_source_block(object_name=[\"MEMORY1\", \"MEMORY1_1\"], input_power=\"5W\")" + ] + }, + { + "cell_type": "markdown", + "id": "ad3c98d4", + "metadata": {}, + "source": [ + "## Assign boundaries\n", + "\n", + "Assign the opening and grille." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7534a897", + "metadata": {}, + "outputs": [], + "source": [ + "region = ipk.modeler[\"Region\"]\n", + "ipk.assign_openings(air_faces=region.bottom_face_x.id)\n", + "ipk.assign_grille(air_faces=region.top_face_x.id, free_area_ratio=0.8)" + ] + }, + { + "cell_type": "markdown", + "id": "5b16ac9c", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create the setup. Properties can be set up from the ``setup`` object\n", + "with getters and setters. They don't have to perfectly match the property\n", + "syntax." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdb3dbb1", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = ipk.create_setup()\n", + "setup1[\"FlowRegime\"] = \"Turbulent\"\n", + "setup1[\"Max Iterations\"] = 5\n", + "setup1[\"Solver Type Pressure\"] = \"flex\"\n", + "setup1[\"Solver Type Temperature\"] = \"flex\"\n", + "ipk.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "13303ac3", + "metadata": {}, + "source": [ + "## Export project to step file\n", + "\n", + "Export the project to the step file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cc53d5a", + "metadata": {}, + "outputs": [], + "source": [ + "filename = ipk.design_name\n", + "file_path = os.path.join(ipk.working_directory, filename + \".step\")\n", + "ipk.export_3d_model(\n", + " file_name=filename,\n", + " file_path=ipk.working_directory,\n", + " file_format=\".step\",\n", + " assignment_to_export=[],\n", + " assignment_to_remove=[],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "583d8203", + "metadata": {}, + "source": [ + "## Export configuration files\n", + "\n", + "Export the configuration files. You can optionally disable the export and\n", + "import sections. Supported formats are JSON and TOML files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "713cbd29", + "metadata": {}, + "outputs": [], + "source": [ + "conf_file = ipk.configurations.export_config(\n", + " os.path.join(ipk.working_directory, \"config.toml\")\n", + ")\n", + "ipk.close_project()" + ] + }, + { + "cell_type": "markdown", + "id": "529ed489", + "metadata": {}, + "source": [ + "## Create project\n", + "\n", + "Create an Icepak project and import the step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ee05c40", + "metadata": {}, + "outputs": [], + "source": [ + "new_project = os.path.join(temp_folder.name, \"example.aedt\")\n", + "app = ansys.aedt.core.Icepak(version=AEDT_VERSION, project=new_project)\n", + "app.modeler.import_3d_cad(file_path)" + ] + }, + { + "cell_type": "markdown", + "id": "d1beca68", + "metadata": {}, + "source": [ + "## Import and apply configuration file\n", + "\n", + "Import and apply the configuration file. You can apply all or part of the\n", + "JSON file that you import using options in the ``configurations`` object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20dc05fb", + "metadata": {}, + "outputs": [], + "source": [ + "out = app.configurations.import_config(conf_file)\n", + "is_conf_imported = app.configurations.results.global_import_success" + ] + }, + { + "cell_type": "markdown", + "id": "89293ad8", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "Close the project and release AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b46575f", + "metadata": {}, + "outputs": [], + "source": [ + "app.release_desktop()\n", + "time.sleep(3) # Allow AEDT to shut down before cleaning the temporary project folder." + ] + }, + { + "cell_type": "markdown", + "id": "a37e2f7f", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f50c07fe", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/index.rst.txt b/version/dev/_sources/examples/aedt_general/index.rst.txt new file mode 100644 index 00000000..fb57196c --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/index.rst.txt @@ -0,0 +1,81 @@ +Pre-processing and post-processing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Provides examples of some general AEDT pre-processing and post-processing capabilities. + + +.. grid:: 2 + + .. grid-item-card:: Configuration files + :padding: 2 2 2 2 + :link: configuration_files + :link-type: doc + + .. image:: _static/configuration_file_icepak.png + :alt: Configuration file + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to export configuration files and reuse them to import in a new project. + + .. grid-item-card:: Modeler + :padding: 2 2 2 2 + :link: modeler/index + :link-type: doc + + .. image:: _static/modeler.png + :alt: Modeler + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some modeler capabilities. + + .. grid-item-card:: Optimetrics setup + :padding: 2 2 2 2 + :link: optimetrics + :link-type: doc + + .. image:: _static/optimetrics.png + :alt: Optimetrics + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a project in HFSS and create all optimetrics setups. + + .. grid-item-card:: Components + :padding: 2 2 2 2 + :link: components/index + :link-type: doc + + .. image:: _static/components.png + :alt: Components + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some 3D component capabilities. + + .. grid-item-card:: Report + :padding: 2 2 2 2 + :link: report/index + :link-type: doc + + .. image:: _static/touchstone.png + :alt: Components + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some report capabilities. + + +.. toctree:: + :hidden: + + configuration_files + modeler/index + optimetrics + components/index + report/index \ No newline at end of file diff --git a/version/dev/_sources/examples/aedt_general/modeler/circuit_schematic.ipynb.txt b/version/dev/_sources/examples/aedt_general/modeler/circuit_schematic.ipynb.txt new file mode 100644 index 00000000..3fda9677 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/modeler/circuit_schematic.ipynb.txt @@ -0,0 +1,377 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1ff2fe6e", + "metadata": {}, + "source": [ + "# Circuit schematic creation and analysis\n", + "\n", + "This example shows how to build a circuit schematic\n", + "and run a transient circuit simulation." + ] + }, + { + "cell_type": "markdown", + "id": "89bbb35f", + "metadata": {}, + "source": [ + "\n", + "\n", + "Keywords: **AEDT**, **Circuit**, **Schematic**." + ] + }, + { + "cell_type": "markdown", + "id": "6baa655a", + "metadata": {}, + "source": [ + "## Import packages and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc6464a", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "f856ba50", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c922052", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "8ac3b1ac", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca2ba027", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "cb41e9a7", + "metadata": {}, + "source": [ + "## Launch AEDT with Circuit\n", + "\n", + "Launch AEDT with Circuit. The [pyaedt.Desktop](\n", + "https://aedt.docs.pyansys.com/version/stable/API/_autosummary/pyaedt.desktop.Desktop.html#pyaedt.desktop.Desktop)\n", + "class initializes AEDT and starts the specified version in the specified mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37f18a4c", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(temp_folder.name, \"CircuitExample\"),\n", + " design=\"Simple\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "\n", + "circuit.modeler.schematic.schematic_units = \"mil\"" + ] + }, + { + "cell_type": "markdown", + "id": "7776ff50", + "metadata": {}, + "source": [ + "## Create circuit setup\n", + "\n", + "Create and customize a linear network analysis (LNA) setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f14cfd6", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = circuit.create_setup(\"MyLNA\")\n", + "setup1.props[\"SweepDefinition\"][\"Data\"] = \"LINC 0GHz 4GHz 10001\"" + ] + }, + { + "cell_type": "markdown", + "id": "6cef7b23", + "metadata": {}, + "source": [ + "## Place components\n", + "\n", + "Place components such as an inductor, resistor, and capacitor. The ``location`` argument\n", + "provides the ``[x, y]`` coordinates to place the component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cef90bba", + "metadata": {}, + "outputs": [], + "source": [ + "inductor = circuit.modeler.schematic.create_inductor(\n", + " name=\"L1\", value=1e-9, location=[0, 0]\n", + ")\n", + "resistor = circuit.modeler.schematic.create_resistor(\n", + " name=\"R1\", value=50, location=[500, 0]\n", + ")\n", + "capacitor = circuit.modeler.schematic.create_capacitor(\n", + " name=\"C1\", value=1e-12, location=[1000, 0]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "34dfe742", + "metadata": {}, + "source": [ + "## Get all pins\n", + "\n", + "The component pins are instances of the\n", + "``ansys.aedt.core.modeler.circuits.objct3dcircuit.CircuitPins`` class and\n", + "provide access to the\n", + "pin location, net connectivity, and the ``connect_to_component()`` method, which\n", + "can be used to connect components in the schematic\n", + "as demonstrated in this example." + ] + }, + { + "cell_type": "markdown", + "id": "0f99e9bc", + "metadata": {}, + "source": [ + "## Place a port and ground\n", + "\n", + "Place a port and a ground in the schematic." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30483c67", + "metadata": {}, + "outputs": [], + "source": [ + "port = circuit.modeler.components.create_interface_port(\n", + " name=\"myport\", location=[-300, 50]\n", + ")\n", + "gnd = circuit.modeler.components.create_gnd(location=[1200, -100])" + ] + }, + { + "cell_type": "markdown", + "id": "6455d851", + "metadata": {}, + "source": [ + "## Connect components\n", + "\n", + "Connect components with wires in the schematic. The ``connect_to_component()``\n", + "method is used to create connections between pins." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "055ddebf", + "metadata": {}, + "outputs": [], + "source": [ + "port.pins[0].connect_to_component(assignment=inductor.pins[0], use_wire=True)\n", + "inductor.pins[1].connect_to_component(assignment=resistor.pins[1], use_wire=True)\n", + "resistor.pins[0].connect_to_component(assignment=capacitor.pins[0], use_wire=True)\n", + "capacitor.pins[1].connect_to_component(assignment=gnd.pins[0], use_wire=True)" + ] + }, + { + "cell_type": "markdown", + "id": "6c634aac", + "metadata": {}, + "source": [ + "## Create transient setup\n", + "\n", + "Create a transient setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "958d757a", + "metadata": {}, + "outputs": [], + "source": [ + "setup2 = circuit.create_setup(\n", + " name=\"MyTransient\", setup_type=circuit.SETUPS.NexximTransient\n", + ")\n", + "setup2.props[\"TransientData\"] = [\"0.01ns\", \"200ns\"]\n", + "setup3 = circuit.create_setup(name=\"MyDC\", setup_type=circuit.SETUPS.NexximDC)" + ] + }, + { + "cell_type": "markdown", + "id": "c7fc4dee", + "metadata": {}, + "source": [ + "## Solve transient setup\n", + "\n", + "Solve the transient setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ff5d69e", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.analyze_setup(\"MyLNA\")\n", + "circuit.export_fullwave_spice()" + ] + }, + { + "cell_type": "markdown", + "id": "faeae356", + "metadata": {}, + "source": [ + "## Create report\n", + "\n", + "Create a report displaying the scattering parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0881719f", + "metadata": {}, + "outputs": [], + "source": [ + "solutions = circuit.post.get_solution_data(\n", + " expressions=circuit.get_traces_for_plot(category=\"S\"),\n", + ")\n", + "solutions.enable_pandas_output = True\n", + "real, imag = solutions.full_matrix_real_imag\n", + "print(real)" + ] + }, + { + "cell_type": "markdown", + "id": "74918f99", + "metadata": {}, + "source": [ + "## Create plot\n", + "\n", + "Create a plot based on solution data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "773186ce", + "metadata": {}, + "outputs": [], + "source": [ + "fig = solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "246e2820", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "829b0f0a", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e03f22ab", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc25e82b", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/modeler/coordinate_system.ipynb.txt b/version/dev/_sources/examples/aedt_general/modeler/coordinate_system.ipynb.txt new file mode 100644 index 00000000..8b39c80b --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/modeler/coordinate_system.ipynb.txt @@ -0,0 +1,805 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "bee48013", + "metadata": {}, + "source": [ + "# Coordinate system creation\n", + "\n", + "This example shows how to use PyAEDT to create and modify coordinate systems in the modeler.\n", + "\n", + "Keywords: **AEDT**, **modeler**, **coordinate system**." + ] + }, + { + "cell_type": "markdown", + "id": "f26a99d6", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3acadd8b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da8f43c6", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "d10e6491", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8afad983", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open the AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "8d4e06cc", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "646254f9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "29894a90", + "metadata": {}, + "source": [ + "## Launch AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85f315d6", + "metadata": {}, + "outputs": [], + "source": [ + "d = ansys.aedt.core.launch_desktop(\n", + " version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "397e85e8", + "metadata": {}, + "source": [ + "## Insert HFSS design\n", + "\n", + "Insert an HFSS design with the default name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cdfc79a", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"CoordSysDemo.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(version=AEDT_VERSION, project=project_name)" + ] + }, + { + "cell_type": "markdown", + "id": "b57f08b9", + "metadata": {}, + "source": [ + "## Create coordinate system\n", + "\n", + "The coordinate system is centered on the global origin and has the axis\n", + "aligned to the global coordinate system. The new coordinate system is\n", + "saved in the object ``cs1``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6a1751d", + "metadata": {}, + "outputs": [], + "source": [ + "cs1 = hfss.modeler.create_coordinate_system()" + ] + }, + { + "cell_type": "markdown", + "id": "f5c834f5", + "metadata": {}, + "source": [ + "## Modify coordinate system\n", + "\n", + "The ``cs1`` object exposes properties and methods to manipulate the\n", + "coordinate system. The origin can be changed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cde75fe5", + "metadata": {}, + "outputs": [], + "source": [ + "cs1[\"OriginX\"] = 10\n", + "cs1.props[\"OriginY\"] = 10\n", + "cs1.props[\"OriginZ\"] = 10" + ] + }, + { + "cell_type": "markdown", + "id": "80c7997e", + "metadata": {}, + "source": [ + "The orientation of the coordinate system can be modified by\n", + "updating the direction vectors for the coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9aba952d", + "metadata": {}, + "outputs": [], + "source": [ + "ypoint = [0, -1, 0]\n", + "cs1.props[\"YAxisXvec\"] = ypoint[0]\n", + "cs1.props[\"YAxisYvec\"] = ypoint[1]\n", + "cs1.props[\"YAxisZvec\"] = ypoint[2]" + ] + }, + { + "cell_type": "markdown", + "id": "b437f257", + "metadata": {}, + "source": [ + "## Rename coordinate system\n", + "\n", + "Rename the coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddf6e2c5", + "metadata": {}, + "outputs": [], + "source": [ + "cs1.rename(\"newCS\")" + ] + }, + { + "cell_type": "markdown", + "id": "672446ce", + "metadata": {}, + "source": [ + "## Change coordinate system mode\n", + "\n", + "Use the ``change_cs_mode`` method to change the mode. Options are:\n", + "\n", + "- ``0`` for axis/position\n", + "- ``1`` for Euler angle ZXZ\n", + "- ``2`` for Euler angle ZYZ\n", + "\n", + "Here ``1`` sets Euler angle ZXZ as the mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27b2aa9f", + "metadata": {}, + "outputs": [], + "source": [ + "cs1.change_cs_mode(1)" + ] + }, + { + "cell_type": "markdown", + "id": "ca0dec06", + "metadata": {}, + "source": [ + "The following lines use the ZXZ Euler angle definition to rotate the coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4479a6b", + "metadata": {}, + "outputs": [], + "source": [ + "cs1.props[\"Phi\"] = \"10deg\"\n", + "cs1.props[\"Theta\"] = \"22deg\"\n", + "cs1.props[\"Psi\"] = \"30deg\"" + ] + }, + { + "cell_type": "markdown", + "id": "d9556654", + "metadata": {}, + "source": [ + "## Delete coordinate system\n", + "\n", + "Delete the coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3dc286a", + "metadata": {}, + "outputs": [], + "source": [ + "cs1.delete()" + ] + }, + { + "cell_type": "markdown", + "id": "26ee64b8", + "metadata": {}, + "source": [ + "## Define a new coordinate system\n", + "\n", + "Create a coordinate system by defining the axes. You can\n", + "specify all coordinate system properties as shown here." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90f70671", + "metadata": {}, + "outputs": [], + "source": [ + "cs2 = hfss.modeler.create_coordinate_system(\n", + " name=\"CS2\",\n", + " origin=[1, 2, 3.5],\n", + " mode=\"axis\",\n", + " x_pointing=[1, 0, 1],\n", + " y_pointing=[0, -1, 0],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f63f98b1", + "metadata": {}, + "source": [ + "A new coordinate system can also be created based on the Euler angle convention." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2333d5d", + "metadata": {}, + "outputs": [], + "source": [ + "cs3 = hfss.modeler.create_coordinate_system(\n", + " name=\"CS3\", origin=[2, 2, 2], mode=\"zyz\", phi=10, theta=20, psi=30\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bb7d7eba", + "metadata": {}, + "source": [ + "Create a coordinate system that is defined by standard views in the modeler. The options are:\n", + "\n", + "- ``\"iso\"``\n", + "- ``\"XY\"``\n", + "- ``\"XZ\"``\n", + "- ``\"XY\"``\n", + "\n", + "Here ``\"iso\"`` is specified. The axes are set automatically." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68805d66", + "metadata": {}, + "outputs": [], + "source": [ + "cs4 = hfss.modeler.create_coordinate_system(\n", + " name=\"CS4\", origin=[1, 0, 0], reference_cs=\"CS3\", mode=\"view\", view=\"iso\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b0909a16", + "metadata": {}, + "source": [ + "## Create coordinate system by defining axis and angle rotation\n", + "\n", + "Create a coordinate system by defining the axis and angle rotation. When you\n", + "specify the axis and angle rotation, this data is automatically translated\n", + "to Euler angles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9509545b", + "metadata": {}, + "outputs": [], + "source": [ + "cs5 = hfss.modeler.create_coordinate_system(\n", + " name=\"CS5\", mode=\"axisrotation\", u=[1, 0, 0], theta=123\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5cd5ffde", + "metadata": {}, + "source": [ + "Face coordinate systems are bound to an object face.\n", + "First create a box and then define the face coordinate system on one of its\n", + "faces. To create the reference face for the face coordinate system, you must\n", + "specify starting and ending points for the axis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70456bec", + "metadata": {}, + "outputs": [], + "source": [ + "box = hfss.modeler.create_box([0, 0, 0], [2, 2, 2])\n", + "face = box.faces[0]\n", + "fcs1 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face.edges[0], axis_position=face.edges[1], name=\"FCS1\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9dd50d16", + "metadata": {}, + "source": [ + "Create a face coordinate system centered on the face with the X axis pointing\n", + "to the edge vertex." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ab874e0", + "metadata": {}, + "outputs": [], + "source": [ + "fcs2 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face, axis_position=face.edges[0].vertices[0], name=\"FCS2\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "aa4870db", + "metadata": {}, + "source": [ + "Swap the X axis and Y axis of the face coordinate system. The X axis is the\n", + "pointing ``axis_position`` by default. You can optionally select the Y axis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1da0a161", + "metadata": {}, + "outputs": [], + "source": [ + "fcs3 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face, axis_position=face.edges[0], axis=\"Y\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f37507bc", + "metadata": {}, + "source": [ + "The face coordinate system can also be rotated by changing the\n", + "reference axis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9fccb22", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "fcs3.props[\"WhichAxis\"] = \"X\"" + ] + }, + { + "cell_type": "markdown", + "id": "7ae751d7", + "metadata": {}, + "source": [ + "### Rotate the coordinate system\n", + "\n", + "Apply a rotation around the Z axis. The Z axis of a face coordinate system\n", + "is always orthogonal to the face. A rotation can be applied at definition.\n", + "Rotation is expressed in degrees." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fbd319b", + "metadata": {}, + "outputs": [], + "source": [ + "fcs4 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face, axis_position=face.edges[1], rotation=10.3\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "632572d7", + "metadata": {}, + "source": [ + "Rotation can also be changed after coordinate system creation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38250aed", + "metadata": {}, + "outputs": [], + "source": [ + "fcs4.props[\"ZRotationAngle\"] = \"3deg\"" + ] + }, + { + "cell_type": "markdown", + "id": "45a83443", + "metadata": {}, + "source": [ + "### Offset the coordinate system\n", + "\n", + "Apply an offset to the X axis and Y axis of a face coordinate system.\n", + "The offset is in respect to the face coordinate system itself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b62b7c8", + "metadata": {}, + "outputs": [], + "source": [ + "fcs5 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face, axis_position=face.edges[2], offset=[0.5, 0.3]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6a359e07", + "metadata": {}, + "source": [ + "The offset can be changed after the coordinate system has been created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb547228", + "metadata": {}, + "outputs": [], + "source": [ + "fcs5.props[\"XOffset\"] = \"0.2mm\"\n", + "fcs5.props[\"YOffset\"] = \"0.1mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "c84f9e6f", + "metadata": {}, + "source": [ + "### Create a dependent coordinate system\n", + "\n", + "The use of dependent coordinate systems can simplify model creation. The following\n", + "cell shows how to create a coordinate system whose reference is the face coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d71a5964", + "metadata": {}, + "outputs": [], + "source": [ + "face = box.faces[1]\n", + "fcs6 = hfss.modeler.create_face_coordinate_system(\n", + " face=face, origin=face, axis_position=face.edges[0]\n", + ")\n", + "cs_fcs = hfss.modeler.create_coordinate_system(\n", + " name=\"CS_FCS\", origin=[0, 0, 0], reference_cs=fcs6.name, mode=\"view\", view=\"iso\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a30440fb", + "metadata": {}, + "source": [ + "### Create object coordinate systems\n", + "\n", + "A coordinate system can also be defined relative to elements\n", + "belonging to an object. For example, the coordinate system can be\n", + "connected to an object face." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e6a4e7d", + "metadata": {}, + "outputs": [], + "source": [ + "obj_cs = hfss.modeler.create_object_coordinate_system(\n", + " assignment=box,\n", + " origin=box.faces[0],\n", + " x_axis=box.edges[0],\n", + " y_axis=[0, 0, 0],\n", + " name=\"box_obj_cs\",\n", + ")\n", + "obj_cs.rename(\"new_obj_cs\")" + ] + }, + { + "cell_type": "markdown", + "id": "95cc6233", + "metadata": {}, + "source": [ + "Create an object coordinate system whose origin is linked to the edge of an object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ced0425", + "metadata": {}, + "outputs": [], + "source": [ + "obj_cs_1 = hfss.modeler.create_object_coordinate_system(\n", + " assignment=box.name,\n", + " origin=box.edges[0],\n", + " x_axis=[1, 0, 0],\n", + " y_axis=[0, 1, 0],\n", + " name=\"obj_cs_1\",\n", + ")\n", + "obj_cs_1.set_as_working_cs()" + ] + }, + { + "cell_type": "markdown", + "id": "189094c7", + "metadata": {}, + "source": [ + "Create an object coordinate system with an origin specified on a point within an object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83266e36", + "metadata": {}, + "outputs": [], + "source": [ + "obj_cs_2 = hfss.modeler.create_object_coordinate_system(\n", + " assignment=box.name,\n", + " origin=[0, 0.8, 0],\n", + " x_axis=[1, 0, 0],\n", + " y_axis=[0, 1, 0],\n", + " name=\"obj_cs_2\",\n", + ")\n", + "new_obj_cs_2 = hfss.modeler.duplicate_coordinate_system_to_global(obj_cs_2)\n", + "obj_cs_2.delete()" + ] + }, + { + "cell_type": "markdown", + "id": "5073407b", + "metadata": {}, + "source": [ + "Create an object coordinate system with an origin on the vertex." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c26a07f3", + "metadata": {}, + "outputs": [], + "source": [ + "obj_cs_3 = hfss.modeler.create_object_coordinate_system(\n", + " obj=box.name,\n", + " origin=box.vertices[1],\n", + " x_axis=box.faces[2],\n", + " y_axis=box.faces[4],\n", + " name=\"obj_cs_3\",\n", + ")\n", + "obj_cs_3.props[\"MoveToEnd\"] = False\n", + "obj_cs_3.update()" + ] + }, + { + "cell_type": "markdown", + "id": "2d312a2c", + "metadata": {}, + "source": [ + "### Get all coordinate systems\n", + "\n", + "Easily retrieve and subsequently manipulate all coordinate systems." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b767f626", + "metadata": {}, + "outputs": [], + "source": [ + "css = hfss.modeler.coordinate_systems\n", + "names = [i.name for i in css]\n", + "print(names)" + ] + }, + { + "cell_type": "markdown", + "id": "5e095df1", + "metadata": {}, + "source": [ + "## Select coordinate system\n", + "\n", + "Select an existing coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c64dca5", + "metadata": {}, + "outputs": [], + "source": [ + "css = hfss.modeler.coordinate_systems\n", + "cs_selected = css[0]\n", + "cs_selected.delete()" + ] + }, + { + "cell_type": "markdown", + "id": "c8bd8046", + "metadata": {}, + "source": [ + "## Get point coordinate under another coordinate system\n", + "\n", + "Get a point coordinate under another coordinate system. A point coordinate\n", + "can be translated in respect to any coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f130546", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.create_box([-10, -10, -10], [20, 20, 20], \"Box1\")\n", + "p = hfss.modeler[\"Box1\"].faces[0].vertices[0].position\n", + "print(\"Global: \", p)\n", + "p2 = hfss.modeler.global_to_cs(p, \"CS5\")\n", + "print(\"CS5 :\", p2)" + ] + }, + { + "cell_type": "markdown", + "id": "14e9014b", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "Close the project and release AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8886feb", + "metadata": {}, + "outputs": [], + "source": [ + "d.release_desktop()\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "709f1852", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f3466b0", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/modeler/index.rst.txt b/version/dev/_sources/examples/aedt_general/modeler/index.rst.txt new file mode 100644 index 00000000..b1884194 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/modeler/index.rst.txt @@ -0,0 +1,67 @@ +Modeler +~~~~~~~ +These examples use PyAEDT to show some modeler capabilities. + +.. grid:: 2 + + .. grid-item-card:: Coordinate system creation + :padding: 2 2 2 2 + :link: coordinate_system + :link-type: doc + + .. image:: _static/coordinate_system.png + :alt: Coordinate system + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create and modify coordinate systems in the modeler. + + + .. grid-item-card:: Polyline creation + :padding: 2 2 2 2 + :link: polyline + :link-type: doc + + .. image:: _static/polyline.png + :alt: Polyline + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create and manipulate polylines. + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: circuit_schematic + :link-type: doc + + .. image:: _static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Circuit Netlist to Schematic + :padding: 2 2 2 2 + :link: netlist_to_schematic + :link-type: doc + + .. image:: _static/netlist.png + :alt: Netlist + :width: 250px + :height: 250px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + +.. toctree:: + :hidden: + + coordinate_system + polyline + circuit_schematic + netlist_to_schematic diff --git a/version/dev/_sources/examples/aedt_general/modeler/netlist_to_schematic.ipynb.txt b/version/dev/_sources/examples/aedt_general/modeler/netlist_to_schematic.ipynb.txt new file mode 100644 index 00000000..16ea3f2a --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/modeler/netlist_to_schematic.ipynb.txt @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6962e662", + "metadata": {}, + "source": [ + "# Circuit Netlist to Schematic\n", + "\n", + "This example shows how to create components\n", + "in the circuit schematic editor from a netlist file.\n", + "\n", + "Note that HSPICE files are fully supported and that broad coverage is provided for many other formats.\n", + "\n", + "Keywords: **Circuit**, **netlist**." + ] + }, + { + "cell_type": "markdown", + "id": "dad3abb9", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50abe18c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "22ec7bd9", + "metadata": {}, + "source": [ + "## Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29728a64", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "556f7ace", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37c8e9e3", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "2e7011ad", + "metadata": {}, + "source": [ + "## Launch AEDT with Circuit\n", + "\n", + "Launch AEDT with Circuit. The `ansys.aedt.core.Desktop` class initializes AEDT\n", + "and starts it on the specified version in the specified graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "202b050b", + "metadata": {}, + "outputs": [], + "source": [ + "netlist = ansys.aedt.core.downloads.download_netlist(destination=temp_folder.name)\n", + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(temp_folder.name, \"NetlistExample\"),\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ff617d7f", + "metadata": {}, + "source": [ + "## Define a parameter\n", + "\n", + "Specify the voltage as a parameter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30f4b738", + "metadata": {}, + "outputs": [], + "source": [ + "circuit[\"Voltage\"] = \"5\"" + ] + }, + { + "cell_type": "markdown", + "id": "b81e7da4", + "metadata": {}, + "source": [ + "## Create schematic from netlist file\n", + "\n", + "Create a schematic from a netlist file. The ``create_schematic_from_netlist()``\n", + "method reads the netlist file and parses it. All components are parsed,\n", + "but only these categories are mapped: R, L, C, Q, U, J, V, and I." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c084fd9d", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.create_schematic_from_netlist(netlist)" + ] + }, + { + "cell_type": "markdown", + "id": "6397525e", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d32e362", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "a7ded304", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b39b8dc9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/modeler/polyline.ipynb.txt b/version/dev/_sources/examples/aedt_general/modeler/polyline.ipynb.txt new file mode 100644 index 00000000..2f726b05 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/modeler/polyline.ipynb.txt @@ -0,0 +1,754 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f49d1cb5", + "metadata": {}, + "source": [ + "# Polyline creation\n", + "\n", + "This example shows how to use PyAEDT to create and manipulate polylines.\n", + "\n", + "Keywords: **AEDT**, **modeler**, **polyline**." + ] + }, + { + "cell_type": "markdown", + "id": "2440b94a", + "metadata": {}, + "source": [ + "## Import packages and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27efadf9", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ce31d1b", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "7a444ca5", + "metadata": {}, + "source": [ + "Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "963b5f10", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "4cf55c46", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03089176", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "4004649f", + "metadata": {}, + "source": [ + "## Create Maxwell 3D object\n", + "\n", + "Create a `Maxwell3d` object and set the unit type to ``\"mm\"``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6a39beb", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"polyline.aedt\")\n", + "maxwell = ansys.aedt.core.Maxwell3d(\n", + " project=project_name,\n", + " solution_type=\"Transient\",\n", + " design=\"test_polyline_3D\",\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")\n", + "maxwell.modeler.model_units = \"mm\"\n", + "modeler = maxwell.modeler" + ] + }, + { + "cell_type": "markdown", + "id": "17a2f454", + "metadata": {}, + "source": [ + "## Define variables\n", + "\n", + "Define two design variables as parameters for the polyline objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82af8b12", + "metadata": {}, + "outputs": [], + "source": [ + "maxwell[\"p1\"] = \"100mm\"\n", + "maxwell[\"p2\"] = \"71mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "c8cf014a", + "metadata": {}, + "source": [ + "## Input data\n", + "\n", + "Input data. All data for the polyline functions can be entered as either floating point\n", + "values or strings. Floating point values are assumed to be in model units\n", + "(``maxwell.modeler.model_units``)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6947c80a", + "metadata": {}, + "outputs": [], + "source": [ + "test_points = [\n", + " [\"0mm\", \"p1\", \"0mm\"],\n", + " [\"-p1\", \"0mm\", \"0mm\"],\n", + " [\"-p1/2\", \"-p1/2\", \"0mm\"],\n", + " [\"0mm\", \"0mm\", \"0mm\"],\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "ff25aa65", + "metadata": {}, + "source": [ + "## Create polyline primitives\n", + "\n", + "The following examples are for creating polyline primitives." + ] + }, + { + "cell_type": "markdown", + "id": "fcf56a97", + "metadata": {}, + "source": [ + "### Create line primitive\n", + "\n", + "Create a line primitive. The basic polyline command takes a list of positions\n", + "(``[X, Y, Z]`` coordinates) and creates a polyline object with one or more\n", + "segments. The supported segment types are ``Line``, ``Arc`` (3 points),\n", + "``AngularArc`` (center-point + angle), and ``Spline``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d665f243", + "metadata": {}, + "outputs": [], + "source": [ + "line1 = modeler.create_polyline(points=test_points[0:2], name=\"PL01_line\")\n", + "print(\"Created Polyline with name: {}\".format(modeler.objects[line1.id].name))\n", + "print(\"Segment types : {}\".format([s.type for s in line1.segment_types]))\n", + "print(\"primitive id = {}\".format(line1.id))" + ] + }, + { + "cell_type": "markdown", + "id": "beebcd21", + "metadata": {}, + "source": [ + "### Create arc primitive\n", + "\n", + "Create an arc primitive. The ``position_list`` parameter must contain at\n", + "least three position values. The first three position values are used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0112f0c", + "metadata": {}, + "outputs": [], + "source": [ + "line2 = modeler.create_polyline(\n", + " points=test_points[0:3], segment_type=\"Arc\", name=\"PL02_arc\"\n", + ")\n", + "print(\n", + " \"Created object with id {} and name {}.\".format(\n", + " line2.id, modeler.objects[line2.id].name\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7b75dfe7", + "metadata": {}, + "source": [ + "### Create spline primitive\n", + "\n", + "Create a spline primitive. Defining the segment using a ``PolylineSegment``\n", + "object allows you to provide additional input parameters for the spine, such\n", + "as the number of points (in this case 4). The ``points`` parameter\n", + "must contain at least four position values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6da9e0c7", + "metadata": {}, + "outputs": [], + "source": [ + "line3 = modeler.create_polyline(\n", + " points=test_points,\n", + " segment_type=modeler.polyline_segment(\"Spline\", num_points=4),\n", + " name=\"PL03_spline_4pt\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "262b96ea", + "metadata": {}, + "source": [ + "### Create center-point arc primitive\n", + "\n", + "Create a center-point arc primitive. A center-point arc segment is defined\n", + "by a starting point, a center point, and an angle of rotation around the\n", + "center point. The rotation occurs in a plane parallel to the XY, YZ, or ZX\n", + "plane of the active coordinate system. The starting point and the center point\n", + "must therefore have one coordinate value (X, Y, or Z) with the same value.\n", + "\n", + "In this first code example, ``start-point`` and ``center-point`` have a common\n", + "Z position, ``\"0mm\"``. The curve therefore lies in the XY plane at $ z = 0 $." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d791d276", + "metadata": {}, + "outputs": [], + "source": [ + "start_point = [100, 100, 0]\n", + "center_point = [0, 0, 0]\n", + "line4 = modeler.create_polyline(\n", + " points=[start_point],\n", + " segment_type=modeler.polyline_segment(\n", + " \"AngularArc\", arc_center=center_point, arc_angle=\"30deg\"\n", + " ),\n", + " name=\"PL04_center_point_arc\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "396adfc1", + "metadata": {}, + "source": [ + "In this second code example, ``start_point`` and ``center_point`` have the same\n", + "values for the Y and Z coordinates, so the plane or rotation could be either XY or ZX.\n", + "For these special cases when the rotation plane is ambiguous, you can specify\n", + "the plane explicitly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "590cb48a", + "metadata": {}, + "outputs": [], + "source": [ + "start_point = [100, 0, 0]\n", + "center_point = [0, 0, 0]\n", + "line4_xy = modeler.create_polyline(\n", + " points=[start_point],\n", + " segment_type=modeler.polyline_segment(\n", + " \"AngularArc\", arc_center=center_point, arc_angle=\"30deg\", arc_plane=\"XY\"\n", + " ),\n", + " name=\"PL04_center_point_arc_rot_XY\",\n", + ")\n", + "line4_zx = modeler.create_polyline(\n", + " points=[start_point],\n", + " segment_type=modeler.polyline_segment(\n", + " \"AngularArc\", arc_center=center_point, arc_angle=\"30deg\", arc_plane=\"ZX\"\n", + " ),\n", + " name=\"PL04_center_point_arc_rot_ZX\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "da3e5d2c", + "metadata": {}, + "source": [ + "## Create compound polylines\n", + "\n", + "You can pass a list of points to the ``create_polyline()`` method to create a multi-segment\n", + "polyline.\n", + "\n", + "If the type of segment is not specified, all points\n", + "are connected by straight line segments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d59ae20", + "metadata": {}, + "outputs": [], + "source": [ + "line6 = modeler.create_polyline(points=test_points, name=\"PL06_segmented_compound_line\")" + ] + }, + { + "cell_type": "markdown", + "id": "aef89460", + "metadata": {}, + "source": [ + "You can specify the segment type as an optional named argument to\n", + "define the segment type used to connect the points." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e229adc", + "metadata": {}, + "outputs": [], + "source": [ + "line5 = modeler.create_polyline(\n", + " points=test_points, segment_type=[\"Line\", \"Arc\"], name=\"PL05_compound_line_arc\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "49feac8a", + "metadata": {}, + "source": [ + "Setting the named argument ``close_surface=True`` ensures\n", + "that the polyline starting point and\n", + "ending point are the same. You can also explicitly close the\n", + "polyline by setting the last point equal\n", + "to the first point in the list of points." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4478106", + "metadata": {}, + "outputs": [], + "source": [ + "line7 = modeler.create_polyline(\n", + " points=test_points, close_surface=True, name=\"PL07_segmented_compound_line_closed\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "df1555a9", + "metadata": {}, + "source": [ + "Setting the named argument ``cover_surface=True`` also\n", + "covers the polyline and creates a sheet object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c38ed1d4", + "metadata": {}, + "outputs": [], + "source": [ + "line_cover = modeler.create_polyline(\n", + " points=test_points, cover_surface=True, name=\"SPL01_segmented_compound_line\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "33f40045", + "metadata": {}, + "source": [ + "## Insert compound lines\n", + "\n", + "The following examples are for inserting compound lines.\n", + "\n", + "### Insert line segment\n", + "\n", + "Insert a line segment starting at vertex 1 ``[\"100mm\", \"0mm\", \"0mm\"]``\n", + "of an existing polyline and ending at some new point ``[\"90mm\", \"20mm\", \"0mm\"].``\n", + "By numerical comparison of the starting point with the existing vertices of the\n", + "original polyline object, it is determined automatically that the segment is\n", + "inserted after the first segment of the original polyline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8800ea6e", + "metadata": {}, + "outputs": [], + "source": [ + "line8_segment = modeler.create_polyline(\n", + " points=test_points,\n", + " close_surface=True,\n", + " name=\"PL08_segmented_compound_insert_segment\",\n", + ")\n", + "points_line8_segment = line8_segment.points[1]\n", + "insert_point = [\"-100mm\", \"20mm\", \"0mm\"]\n", + "line8_segment.insert_segment(points=[insert_point, points_line8_segment])" + ] + }, + { + "cell_type": "markdown", + "id": "bf733c6c", + "metadata": {}, + "source": [ + "### Insert compound line with insert curve\n", + "\n", + "Insert a compound line starting a line segment at vertex 1 ``[\"100mm\", \"0mm\", \"0mm\"]``\n", + "of an existing polyline and ending at some new point ``[\"90mm\", \"20mm\", \"0mm\"]``.\n", + "By numerical comparison of the starting point, it is determined automatically\n", + "that the segment is inserted after the first segment of the original polyline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc9aa65b", + "metadata": {}, + "outputs": [], + "source": [ + "line8_segment_arc = modeler.create_polyline(\n", + " points=test_points, close_surface=False, name=\"PL08_segmented_compound_insert_arc\"\n", + ")\n", + "\n", + "start_point = line8_segment_arc.vertex_positions[1]\n", + "insert_point1 = [\"90mm\", \"20mm\", \"0mm\"]\n", + "insert_point2 = [40, 40, 0]\n", + "\n", + "line8_segment_arc.insert_segment(\n", + " points=[start_point, insert_point1, insert_point2], segment=\"Arc\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "13b70185", + "metadata": {}, + "source": [ + "### Insert compound line at end of a center-point arc\n", + "\n", + "Insert a compound line at the end of a center-point arc (``type=\"AngularArc\"``).\n", + "This is a special case.\n", + "\n", + "Step 1: Draw a center-point arc." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc47fe73", + "metadata": {}, + "outputs": [], + "source": [ + "start_point = [2200.0, 0.0, 1200.0]\n", + "arc_center_1 = [1400, 0, 800]\n", + "arc_angle_1 = \"43.47deg\"\n", + "\n", + "line_arc = modeler.create_polyline(\n", + " name=\"First_Arc\",\n", + " points=[start_point],\n", + " segment_type=modeler.polyline_segment(\n", + " type=\"AngularArc\", arc_angle=arc_angle_1, arc_center=arc_center_1\n", + " ),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "39727ea8", + "metadata": {}, + "source": [ + "Step 2: Insert a line segment at the end of the arc with a specified end point." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5520fa03", + "metadata": {}, + "outputs": [], + "source": [ + "start_of_line_segment = line_arc.end_point\n", + "end_of_line_segment = [3600, 200, 30]\n", + "line_arc.insert_segment(points=[start_of_line_segment, end_of_line_segment])" + ] + }, + { + "cell_type": "markdown", + "id": "bb1d9d4f", + "metadata": {}, + "source": [ + "Step 3: Append a center-point arc segment to the line object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ad43722", + "metadata": {}, + "outputs": [], + "source": [ + "arc_angle_2 = \"39.716deg\"\n", + "arc_center_2 = [3400, 200, 3800]\n", + "line_arc.insert_segment(\n", + " points=[end_of_line_segment],\n", + " segment=modeler.polyline_segment(\n", + " type=\"AngularArc\", arc_center=arc_center_2, arc_angle=arc_angle_2\n", + " ),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8c98327a", + "metadata": {}, + "source": [ + "You can use the compound polyline definition to complete all three steps in\n", + "a single step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca5ce327", + "metadata": {}, + "outputs": [], + "source": [ + "modeler.create_polyline(\n", + " points=[start_point, end_of_line_segment],\n", + " segment_type=[\n", + " modeler.polyline_segment(\n", + " type=\"AngularArc\", arc_angle=\"43.47deg\", arc_center=arc_center_1\n", + " ),\n", + " modeler.polyline_segment(type=\"Line\"),\n", + " modeler.polyline_segment(\n", + " type=\"AngularArc\", arc_angle=arc_angle_2, arc_center=arc_center_2\n", + " ),\n", + " ],\n", + " name=\"Compound_Polyline_One_Command\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "07d975f6", + "metadata": {}, + "source": [ + "## Insert two 3-point arcs forming a circle\n", + "\n", + "Insert two 3-point arcs forming a circle.\n", + "Note that the last point of the second arc segment is not defined in\n", + "the position list." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33f31c50", + "metadata": {}, + "outputs": [], + "source": [ + "line_three_points = modeler.create_polyline(\n", + " points=[\n", + " [34.1004, 14.1248, 0],\n", + " [27.646, 16.7984, 0],\n", + " [24.9725, 10.3439, 0],\n", + " [31.4269, 7.6704, 0],\n", + " ],\n", + " segment_type=[\"Arc\", \"Arc\"],\n", + " cover_surface=True,\n", + " close_surface=True,\n", + " name=\"line_covered\",\n", + " material=\"vacuum\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "29888823", + "metadata": {}, + "source": [ + "Here is an example of a complex polyline where the number of points is\n", + "insufficient to populate the requested segments. This results in an\n", + "``IndexError`` that PyAEDT catches silently. The return value of the command\n", + "is ``False``, which can be caught at the app level. While this example might\n", + "not be so useful in a Jupyter Notebook, it is important for unit tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "823fc850", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "line_points = [\n", + " [\"67.1332mm\", \"2.9901mm\", \"0mm\"],\n", + " [\"65.9357mm\", \"2.9116mm\", \"0mm\"],\n", + " [\"65.9839mm\", \"1.4562mm\", \"0mm\"],\n", + " [\"66mm\", \"0mm\", \"0mm\"],\n", + " [\"99mm\", \"0mm\", \"0mm\"],\n", + " [\"98.788mm\", \"6.4749mm\", \"0mm\"],\n", + " [\"98.153mm\", \"12.9221mm\", \"0mm\"],\n", + " [\"97.0977mm\", \"19.3139mm\", \"0mm\"],\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "298cc0c0", + "metadata": {}, + "outputs": [], + "source": [ + "line_segments = [\"Line\", \"Arc\", \"Line\", \"Arc\", \"Line\"]\n", + "line_complex1 = modeler.create_polyline(\n", + " points=line_points, segment_type=line_segments, name=\"Polyline_example\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3a81733f", + "metadata": {}, + "source": [ + "Here is an example that provides more points than the segment list requires.\n", + "This is valid usage. The remaining points are ignored." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcc28d29", + "metadata": {}, + "outputs": [], + "source": [ + "line_segments = [\"Line\", \"Arc\", \"Line\", \"Arc\"]\n", + "line_complex2 = modeler.create_polyline(\n", + " line_points, segment_type=line_segments, name=\"Polyline_example2\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5d691024", + "metadata": {}, + "source": [ + "## Save project\n", + "\n", + "Save the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d821a9bc", + "metadata": {}, + "outputs": [], + "source": [ + "maxwell.save_project()\n", + "maxwell.release_desktop()\n", + "time.sleep(3) # Allow AEDT to shut down before cleaning the temporary project folder." + ] + }, + { + "cell_type": "markdown", + "id": "3280f971", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8b91024", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/optimetrics.ipynb.txt b/version/dev/_sources/examples/aedt_general/optimetrics.ipynb.txt new file mode 100644 index 00000000..53094176 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/optimetrics.ipynb.txt @@ -0,0 +1,410 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4f52606c", + "metadata": {}, + "source": [ + "# Optimetrics setup\n", + "\n", + "This example shows how to use PyAEDT to create a project in HFSS and create all optimetrics\n", + "setups.\n", + "\n", + "Keywords: **AEDT**, **General**, **optimetrics**." + ] + }, + { + "cell_type": "markdown", + "id": "0c472ac0", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "418c5f6b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7c2a9f4", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "0a087d51", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69367bf2", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "423b1107", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0899f3a5", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "d69712ed", + "metadata": {}, + "source": [ + "## Initialize HFSS and create variables\n", + "\n", + "Initialize the ``Hfss`` object and create two needed design variables,\n", + "``w1`` and ``w2``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bdd21ba", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"optimetrics.aedt\")\n", + "\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + " solution_type=\"Modal\",\n", + ")\n", + "\n", + "hfss[\"w1\"] = \"1mm\"\n", + "hfss[\"w2\"] = \"100mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "bc12921c", + "metadata": {}, + "source": [ + "## Create waveguide with sheets on it\n", + "\n", + "Create one of the standard waveguide structures and parametrize it.\n", + "You can also create rectangles of waveguide openings and assign ports later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba49bef9", + "metadata": {}, + "outputs": [], + "source": [ + "wg1, p1, p2 = hfss.modeler.create_waveguide(\n", + " [0, 0, 0],\n", + " hfss.AXIS.Y,\n", + " \"WG17\",\n", + " wg_thickness=\"w1\",\n", + " wg_length=\"w2\",\n", + " create_sheets_on_openings=True,\n", + ")\n", + "\n", + "model = hfss.plot(show=False)\n", + "\n", + "model.show_grid = False\n", + "model.plot(os.path.join(hfss.working_directory, \"Image.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "15a49a73", + "metadata": {}, + "source": [ + "## Create wave ports on sheets\n", + "\n", + "Create two wave ports on the sheets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82bd703b", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.wave_port(p1, integration_line=hfss.AxisDir.ZPos, name=\"1\")\n", + "hfss.wave_port(p2, integration_line=hfss.AxisDir.ZPos, name=\"2\")" + ] + }, + { + "cell_type": "markdown", + "id": "0fc1a7dd", + "metadata": {}, + "source": [ + "## Create setup and frequency sweep\n", + "\n", + "Create a setup and a frequency sweep to use as the base for optimetrics\n", + "setups." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60495172", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup()\n", + "hfss.create_linear_step_sweep(\n", + " setup=setup.name,\n", + " unit=\"GHz\",\n", + " start_frequency=1,\n", + " stop_frequency=5,\n", + " step_size=0.1,\n", + " name=\"Sweep1\",\n", + " save_fields=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1e41ddf3", + "metadata": {}, + "source": [ + "## Create optimetrics analyses\n", + "\n", + "### Create parametric analysis\n", + "\n", + "Create a simple optimetrics parametrics analysis with output calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "793806bf", + "metadata": {}, + "outputs": [], + "source": [ + "sweep = hfss.parametrics.add(\"w2\", 90, 200, 5)\n", + "sweep.add_variation(\"w1\", 0.1, 2, 10)\n", + "sweep.add_calculation(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.5GHz\"})\n", + "sweep.add_calculation(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.6GHz\"})" + ] + }, + { + "cell_type": "markdown", + "id": "ee06df67", + "metadata": {}, + "source": [ + "### Create sensitivity analysis\n", + "\n", + "Create an optimetrics sensitivity analysis with output calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaac7425", + "metadata": {}, + "outputs": [], + "source": [ + "sweep2 = hfss.optimizations.add(\n", + " calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.5GHz\"}, optimization_type=\"Sensitivity\"\n", + ")\n", + "sweep2.add_variation(\"w1\", 0.1, 3, 0.5)\n", + "sweep2.add_calculation(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.6GHz\"})" + ] + }, + { + "cell_type": "markdown", + "id": "069d402e", + "metadata": {}, + "source": [ + "### Create an optimization analysis\n", + "\n", + "Create an optimization analysis based on goals and calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d46f3962", + "metadata": {}, + "outputs": [], + "source": [ + "sweep3 = hfss.optimizations.add(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.5GHz\"})\n", + "sweep3.add_variation(\"w1\", 0.1, 3, 0.5)\n", + "sweep3.add_goal(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.6GHz\"})\n", + "sweep3.add_goal(calculation=\"dB(S(1,1))\", ranges={\"Freq\": (\"2.6GHz\", \"5GHz\")})\n", + "sweep3.add_goal(\n", + " calculation=\"dB(S(1,1))\",\n", + " ranges={\"Freq\": (\"2.6GHz\", \"5GHz\")},\n", + " condition=\"Maximize\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "88ec18d7", + "metadata": {}, + "source": [ + "### Create a DesignXplorer optimization\n", + "\n", + "Create a DesignXplorer optimization based on a goal and a calculation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbe32e63", + "metadata": {}, + "outputs": [], + "source": [ + "sweep4 = hfss.optimizations.add(\n", + " calculation=\"dB(S(1,1))\",\n", + " ranges={\"Freq\": \"2.5GHz\"},\n", + " optimization_type=\"DesignExplorer\",\n", + ")\n", + "sweep4.add_goal(calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.6GHz\"})" + ] + }, + { + "cell_type": "markdown", + "id": "fb68fec3", + "metadata": {}, + "source": [ + "### Create a Design of Experiments (DOE)\n", + "\n", + "Create a DOE based on a goal and a calculation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d33c8a0", + "metadata": {}, + "outputs": [], + "source": [ + "sweep5 = hfss.optimizations.add(\n", + " calculation=\"dB(S(1,1))\", ranges={\"Freq\": \"2.5GHz\"}, optimization_type=\"DXDOE\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5b6723d4", + "metadata": {}, + "source": [ + "### Create another DOE\n", + "\n", + "Create another DOE based on a goal and a calculation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd55400a", + "metadata": {}, + "outputs": [], + "source": [ + "region = hfss.modeler.create_region()\n", + "hfss.assign_radiation_boundary_to_objects(region)\n", + "hfss.insert_infinite_sphere(name=\"Infinite_1\")\n", + "sweep6 = hfss.optimizations.add(\n", + " calculation=\"RealizedGainTotal\",\n", + " solution=hfss.nominal_adaptive,\n", + " ranges={\"Freq\": \"5GHz\", \"Theta\": [\"0deg\", \"10deg\", \"20deg\"], \"Phi\": \"0deg\"},\n", + " context=\"Infinite_1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "dd75ffd9", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1cc430d7", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "time.sleep(3) # Allow AEDT to shut down before cleaning the temporary project folder." + ] + }, + { + "cell_type": "markdown", + "id": "d7387e79", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "793f8d70", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/report/automatic_report.ipynb.txt b/version/dev/_sources/examples/aedt_general/report/automatic_report.ipynb.txt new file mode 100644 index 00000000..e292e96f --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/report/automatic_report.ipynb.txt @@ -0,0 +1,321 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5dadd712", + "metadata": {}, + "source": [ + "# Automatic report creation\n", + "\n", + "This example shows how to create reports from a JSON template file.\n", + "\n", + "\n", + "Keywords: **Circuit**, **report**." + ] + }, + { + "cell_type": "markdown", + "id": "1dc1b27c", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Import the required packages. This example uses\n", + "data from the [example-data repository](https://github.com/ansys/example-data/tree/master)\n", + "located in ``pyaedt\\custom_reports``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ebdda7f", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n", + "from IPython.display import Image\n", + "\n", + "# Define constants.\n", + "\n", + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched.\n", + "\n", + "# ## Create temporary directory\n", + "#\n", + "# Create a temporary directory where downloaded data or\n", + "# dumped data can be stored.\n", + "# If you'd like to retrieve the project data for subsequent use,\n", + "# the temporary folder name is given by ``temp_folder.name``.\n", + "\n", + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "\n", + "# ## Launch AEDT with Circuit\n", + "#\n", + "# AEDT is started by instantiating an instance of\n", + "# [pyaedt.Circuit](https://aedt.docs.pyansys.com/version/stable/API/_autosummary/pyaedt.circuit.Circuit.html).\n", + "#\n", + "# ### Application keyword arguments\n", + "#\n", + "# - The argument ``non_graphical`` specifies whether an interactive session is launched or if\n", + "# AEDT is to run in non-graphical mode.\n", + "# - The Boolean parameter ``new_desktop`` specifies if a new instance\n", + "# of AEDT is launched. If it is set to ``False``, the API tries to connect to a running session.\n", + "#\n", + "# This example extracts an archived project. The full path\n", + "# to the extracted project is accessible from the ``cir.project_file`` property." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a744356d", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"custom_reports/\", destination=temp_folder.name\n", + ")\n", + "\n", + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(project_path, \"CISPR25_Radiated_Emissions_Example23R1.aedtz\"),\n", + " non_graphical=NG_MODE,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + ")\n", + "circuit.analyze() # Run the circuit analysis." + ] + }, + { + "cell_type": "markdown", + "id": "daf26126", + "metadata": {}, + "source": [ + "## Create a spectral report\n", + "\n", + "The JSON file is used to customize the report. In a spectral report, you can add limit lines. You can also\n", + "add notes to a report and modify the axes, grid, and legend. Custom reports\n", + "can be created in AEDT in non-graphical mode using version 2023 R2 and later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f1ddcc9", + "metadata": {}, + "outputs": [], + "source": [ + "report1 = circuit.post.create_report_from_configuration(\n", + " os.path.join(project_path, \"Spectrum_CISPR_Basic.json\")\n", + ")\n", + "out = circuit.post.export_report_to_jpg(\n", + " project_path=circuit.working_directory, plot_name=report1.plot_name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a9229167", + "metadata": {}, + "source": [ + "Render the image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2fb9965", + "metadata": {}, + "outputs": [], + "source": [ + "Image(os.path.join(circuit.working_directory, report1.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "a886a238", + "metadata": {}, + "source": [ + "You can customize every aspect of the report. The method ``crate_report_from_configuration()`` reads the\n", + "report configuration from a JSON file and generates the custom report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ef53eea", + "metadata": {}, + "outputs": [], + "source": [ + "report1_full = circuit.post.create_report_from_configuration(\n", + " os.path.join(project_path, \"Spectrum_CISPR_Custom.json\")\n", + ")\n", + "out = circuit.post.export_report_to_jpg(\n", + " circuit.working_directory, report1_full.plot_name\n", + ")\n", + "Image(os.path.join(circuit.working_directory, report1_full.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "7ad2be7e", + "metadata": {}, + "source": [ + "## Create a transient report\n", + "\n", + "The JSON configuration file can be read and modified from the API prior to creating the report.\n", + "The following code modifies the trace rendering prior to creating the report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b780800", + "metadata": {}, + "outputs": [], + "source": [ + "props = ansys.aedt.core.general_methods.read_json(\n", + " os.path.join(project_path, \"Transient_CISPR_Custom.json\")\n", + ")\n", + "\n", + "report2 = circuit.post.create_report_from_configuration(\n", + " report_settings=props, solution_name=\"NexximTransient\"\n", + ")\n", + "out = circuit.post.export_report_to_jpg(circuit.working_directory, report2.plot_name)\n", + "Image(os.path.join(circuit.working_directory, report2.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "feeafc8c", + "metadata": {}, + "source": [ + "The ``props`` dictionary can be used to customize any aspect of an existing report or generate a new report.\n", + "In this example, the name of the curve is customized." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec7cfc56", + "metadata": {}, + "outputs": [], + "source": [ + "props[\"expressions\"] = {\"V(Battery)\": {}, \"V(U1_VDD)\": {}}\n", + "props[\"plot_name\"] = \"Battery Voltage\"\n", + "report3 = circuit.post.create_report_from_configuration(\n", + " report_settings=props, solution_name=\"NexximTransient\"\n", + ")\n", + "out = circuit.post.export_report_to_jpg(circuit.working_directory, report3.plot_name)\n", + "Image(os.path.join(circuit.working_directory, report3.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "c8d4895f", + "metadata": {}, + "source": [ + "## Create an eye diagram\n", + "\n", + "You can use the JSON file to create an eye diagram. The following code includes the eye." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eea5bae6", + "metadata": {}, + "outputs": [], + "source": [ + "report4 = circuit.post.create_report_from_configuration(\n", + " os.path.join(project_path, \"EyeDiagram_CISPR_Basic.json\")\n", + ")\n", + "out = circuit.post.export_report_to_jpg(circuit.working_directory, report4.plot_name)\n", + "Image(os.path.join(circuit.working_directory, report4.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "febf435b", + "metadata": {}, + "outputs": [], + "source": [ + "report4_full = circuit.post.create_report_from_configuration(\n", + " os.path.join(project_path, \"EyeDiagram_CISPR_Custom.json\")\n", + ")\n", + "\n", + "out = circuit.post.export_report_to_jpg(\n", + " circuit.working_directory, report4_full.plot_name\n", + ")\n", + "Image(os.path.join(circuit.working_directory, report4_full.plot_name + \".jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "2354f619", + "metadata": {}, + "source": [ + "## Save project and close AEDT\n", + "\n", + "Save the project and close AEDT. The example has finished running. You can retrieve project files\n", + "from ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3a88862", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "print(\"Project Saved in {}\".format(circuit.project_path))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26138196", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.release_desktop()\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "31e35e19", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "The following cell cleans up the temporary directory and\n", + "removes all project files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d73e15ca", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/report/index.rst.txt b/version/dev/_sources/examples/aedt_general/report/index.rst.txt new file mode 100644 index 00000000..fe31a0b1 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/report/index.rst.txt @@ -0,0 +1,52 @@ +Report +~~~~~~ + +These examples use PyAEDT to show some report capabilities. + +.. grid:: 2 + + .. grid-item-card:: PCIE virtual compliance + :padding: 2 2 2 2 + :link: virtual_compliance + :link-type: doc + + .. image:: _static/virtual_compliance_eye.png + :alt: Virtual compliance + :width: 250px + :height: 200px + :align: center + + This example shows how to generate a compliance report in PyAEDT using the VirtualCompliance class. + + .. grid-item-card:: Touchstone files + :padding: 2 2 2 2 + :link: touchstone_file + :link-type: doc + + .. image:: _static/touchstone_skitrf.png + :alt: Touchstone file + :width: 250px + :height: 200px + :align: center + + This example shows how to use objects in a Touchstone file without opening AEDT. + + .. grid-item-card:: Automatic report creation + :padding: 2 2 2 2 + :link: automatic_report + :link-type: doc + + .. image:: _static/automatic_report.png + :alt: Automatic report + :width: 250px + :height: 200px + :align: center + + This example shows how to create reports from a JSON template file. + +.. toctree:: + :hidden: + + virtual_compliance + touchstone_file + automatic_report diff --git a/version/dev/_sources/examples/aedt_general/report/touchstone_file.ipynb.txt b/version/dev/_sources/examples/aedt_general/report/touchstone_file.ipynb.txt new file mode 100644 index 00000000..e3bc832f --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/report/touchstone_file.ipynb.txt @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3adf874c", + "metadata": {}, + "source": [ + "# Touchstone files\n", + "\n", + "This example shows how to use objects in a Touchstone file without opening AEDT.\n", + "\n", + "To provide the advanced postprocessing features needed for this example, Matplotlib and NumPy\n", + "must be installed on your machine.\n", + "\n", + "This example runs only on Windows using CPython.\n", + "\n", + "Keywords: **Touchstone**, **report**." + ] + }, + { + "cell_type": "markdown", + "id": "16e09ebe", + "metadata": {}, + "source": [ + "## Perform imports\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c676fd25", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import downloads\n", + "from ansys.aedt.core.visualization.advanced.touchstone_parser import \\\n", + " read_touchstone" + ] + }, + { + "cell_type": "markdown", + "id": "c1a10980", + "metadata": {}, + "source": [ + "## Download example data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fc48229", + "metadata": {}, + "outputs": [], + "source": [ + "example_path = downloads.download_touchstone()" + ] + }, + { + "cell_type": "markdown", + "id": "69ce5961", + "metadata": {}, + "source": [ + "## Read the Touchstone file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3738b946", + "metadata": {}, + "outputs": [], + "source": [ + "data = read_touchstone(example_path)" + ] + }, + { + "cell_type": "markdown", + "id": "961e28a0", + "metadata": {}, + "source": [ + "## Plot data\n", + "\n", + "Get the curve plot by category. The following code shows how to plot lists of the return losses,\n", + "insertion losses, next, and fext based on a few inputs and port names." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1a80704", + "metadata": {}, + "outputs": [], + "source": [ + "data.plot_return_losses()\n", + "data.plot_insertion_losses()\n", + "data.plot_next_xtalk_losses(\"U1\")\n", + "data.plot_fext_xtalk_losses(tx_prefix=\"U1\", rx_prefix=\"U7\")" + ] + }, + { + "cell_type": "markdown", + "id": "3b6a4f71", + "metadata": {}, + "source": [ + "## Identify cross-talk\n", + "\n", + "Identify the worst case cross-talk." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64c4ab2e", + "metadata": {}, + "outputs": [], + "source": [ + "worst_rl, global_mean = data.get_worst_curve(\n", + " freq_min=1,\n", + " freq_max=20,\n", + " worst_is_higher=True,\n", + " curve_list=data.get_return_loss_index(),\n", + ")\n", + "worst_il, mean2 = data.get_worst_curve(\n", + " freq_min=1,\n", + " freq_max=20,\n", + " worst_is_higher=False,\n", + " curve_list=data.get_insertion_loss_index(),\n", + ")\n", + "worst_fext, mean3 = data.get_worst_curve(\n", + " freq_min=1,\n", + " freq_max=20,\n", + " worst_is_higher=True,\n", + " curve_list=data.get_fext_xtalk_index_from_prefix(tx_prefix=\"U1\", rx_prefix=\"U7\"),\n", + ")\n", + "worst_next, mean4 = data.get_worst_curve(\n", + " freq_min=1,\n", + " freq_max=20,\n", + " worst_is_higher=True,\n", + " curve_list=data.get_next_xtalk_index(\"U1\"),\n", + ")" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/aedt_general/report/virtual_compliance.ipynb.txt b/version/dev/_sources/examples/aedt_general/report/virtual_compliance.ipynb.txt new file mode 100644 index 00000000..94ba9946 --- /dev/null +++ b/version/dev/_sources/examples/aedt_general/report/virtual_compliance.ipynb.txt @@ -0,0 +1,496 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3896a896", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "# PCIE virtual compliance\n", + "\n", + "This example shows how to generate a compliance report in PyAEDT using\n", + "the ``VirtualCompliance`` class.\n", + "\n", + "Keywords: **Circuit**, **Automatic report**, **virtual compliance**." + ] + }, + { + "cell_type": "markdown", + "id": "a95dfa93", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4c166e5", + "metadata": {}, + "outputs": [], + "source": [ + "import os.path\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b486358", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.visualization.post.compliance import VirtualCompliance" + ] + }, + { + "cell_type": "markdown", + "id": "8005c982", + "metadata": {}, + "source": [ + "## Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "734934e1", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "ff26cef3", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored. In this example, the temporary directory\n", + "in where the example is stored and simulation data is saved.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1dae96d1", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "af832c50", + "metadata": {}, + "source": [ + "## Download example data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09525cb9", + "metadata": {}, + "outputs": [], + "source": [ + "download_folder = ansys.aedt.core.downloads.download_file(\n", + " source=\"pcie_compliance\", destination=temp_folder.name\n", + ")\n", + "project_folder = os.path.join(download_folder, \"project\")\n", + "project_path = os.path.join(project_folder, \"PCIE_GEN5_only_layout.aedtz\")" + ] + }, + { + "cell_type": "markdown", + "id": "b528e4d3", + "metadata": {}, + "source": [ + "## Launch AEDT and solve layout\n", + "\n", + "Open the HFSS 3D Layout project and analyze it using the SIwave solver.\n", + "Before solving, this code ensures that the model is solved from DC to 70GHz and that\n", + "causality and passivity are enforced." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47c713c0", + "metadata": {}, + "outputs": [], + "source": [ + "h3d = ansys.aedt.core.Hfss3dLayout(\n", + " project=project_path, version=AEDT_VERSION, non_graphical=NG_MODE\n", + ")\n", + "h3d.remove_all_unused_definitions()\n", + "h3d.edit_cosim_options(simulate_missing_solution=False)\n", + "h3d.setups[0].sweeps[0].props[\"EnforcePassivity\"] = True\n", + "h3d.setups[0].sweeps[0].props[\"Sweeps\"][\"Data\"] = \"LIN 0MHz 70GHz 0.1GHz\"\n", + "h3d.setups[0].sweeps[0].props[\"EnforceCausality\"] = True\n", + "h3d.setups[0].sweeps[0].update()\n", + "h3d.analyze(cores=NUM_CORES)\n", + "h3d = ansys.aedt.core.Hfss3dLayout()\n", + "touchstone_path = h3d.export_touchstone()" + ] + }, + { + "cell_type": "markdown", + "id": "be510d23", + "metadata": {}, + "source": [ + "## Create LNA project\n", + "\n", + "Use the LNA (linear network analysis) setup to retrieve Touchstone files\n", + "and generate frequency domain reports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46f6bc3f", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = ansys.aedt.core.Circuit(project=h3d.project_name, design=\"Touchstone\")\n", + "status, diff_pairs, comm_pairs = circuit.create_lna_schematic_from_snp(\n", + " input_file=touchstone_path,\n", + " start_frequency=0,\n", + " stop_frequency=70,\n", + " auto_assign_diff_pairs=True,\n", + " separation=\".\",\n", + " pattern=[\"component\", \"pin\", \"net\"],\n", + " analyze=True,\n", + ")\n", + "insertion = circuit.get_all_insertion_loss_list(\n", + " drivers=diff_pairs,\n", + " receivers=diff_pairs,\n", + " drivers_prefix_name=\"X1\",\n", + " receivers_prefix_name=\"U1\",\n", + " math_formula=\"dB\",\n", + " nets=[\"RX0\", \"RX1\", \"RX2\", \"RX3\"],\n", + ")\n", + "return_diff = circuit.get_all_return_loss_list(\n", + " excitations=diff_pairs,\n", + " excitation_name_prefix=\"X1\",\n", + " math_formula=\"dB\",\n", + " nets=[\"RX0\", \"RX1\", \"RX2\", \"RX3\"],\n", + ")\n", + "return_comm = circuit.get_all_return_loss_list(\n", + " excitations=comm_pairs,\n", + " excitation_name_prefix=\"COMMON_X1\",\n", + " math_formula=\"dB\",\n", + " nets=[\"RX0\", \"RX1\", \"RX2\", \"RX3\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0d39d841", + "metadata": {}, + "source": [ + "## Create TDR project\n", + "\n", + "Create a TDR project to compute transient simulation and retrieve\n", + "the TDR measurement on a differential pair.\n", + "The original circuit schematic is duplicated and modified to achieve this target." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "daac9775", + "metadata": {}, + "outputs": [], + "source": [ + "result, tdr_probe_name = circuit.create_tdr_schematic_from_snp(\n", + " input_file=touchstone_path,\n", + " tx_schematic_pins=[\"X1.A2.PCIe_Gen4_RX0_P\"],\n", + " tx_schematic_differential_pins=[\"X1.A3.PCIe_Gen4_RX0_N\"],\n", + " termination_pins=[\"U1.AP26.PCIe_Gen4_RX0_P\", \"U1.AN26.PCIe_Gen4_RX0_N\"],\n", + " differential=True,\n", + " rise_time=35,\n", + " use_convolution=True,\n", + " analyze=True,\n", + " design_name=\"TDR\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a6e802d1", + "metadata": {}, + "source": [ + "## Create AMI project\n", + "\n", + "Create an Ibis AMI project to compute an eye diagram simulation and retrieve\n", + "eye mask violations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a94a0dd", + "metadata": {}, + "outputs": [], + "source": [ + "_, eye_curve_tx, eye_curve_rx = circuit.create_ami_schematic_from_snp(\n", + " input_file=touchstone_path,\n", + " ibis_tx_file=os.path.join(project_folder, \"models\", \"pcieg5_32gt.ibs\"),\n", + " tx_buffer_name=\"1p\",\n", + " rx_buffer_name=\"2p\",\n", + " tx_schematic_pins=[\"U1.AM25.PCIe_Gen4_TX0_CAP_P\"],\n", + " rx_schematic_pins=[\"X1.B2.PCIe_Gen4_TX0_P\"],\n", + " tx_schematic_differential_pins=[\"U1.AL25.PCIe_Gen4_TX0_CAP_N\"],\n", + " rx_schematic_differentialial_pins=[\"X1.B3.PCIe_Gen4_TX0_N\"],\n", + " ibis_tx_component_name=\"Spec_Model\",\n", + " use_ibis_buffer=False,\n", + " differential=True,\n", + " bit_pattern=\"random_bit_count=2.5e3 random_seed=1\",\n", + " unit_interval=\"31.25ps\",\n", + " use_convolution=True,\n", + " analyze=True,\n", + " design_name=\"AMI\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7631c725", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "53239ca6", + "metadata": {}, + "source": [ + "## Create virtual compliance report\n", + "\n", + "Initialize the ``VirtualCompliance`` class\n", + "and set up the main project information needed to generate the report.\n" + ] + }, + { + "cell_type": "markdown", + "id": "cb4d07f4", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "7f0178a9", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "494e3288", + "metadata": {}, + "outputs": [], + "source": [ + "template = os.path.join(download_folder, \"pcie_gen5_templates\", \"main.json\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2b92471", + "metadata": {}, + "outputs": [], + "source": [ + "v = VirtualCompliance(circuit.desktop_class, str(template))" + ] + }, + { + "cell_type": "markdown", + "id": "a279fa69", + "metadata": {}, + "source": [ + "## Customize project and design\n", + "\n", + "Define the path to the project file and the\n", + "design names to be used in each report generation.\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba362b32", + "metadata": {}, + "outputs": [], + "source": [ + "v.project_file = circuit.project_file\n", + "v.reports[\"insertion losses\"].design_name = \"LNA\"\n", + "v.reports[\"return losses\"].design_name = \"LNA\"\n", + "v.reports[\"common mode return losses\"].design_name = \"LNA\"\n", + "v.reports[\"tdr from circuit\"].design_name = \"TDR\"\n", + "v.reports[\"eye1\"].design_name = \"AMI\"\n", + "v.reports[\"eye3\"].design_name = \"AMI\"\n", + "v.parameters[\"erl\"].design_name = \"LNA\"\n", + "v.specs_folder = os.path.join(download_folder, \"readme_pictures\")" + ] + }, + { + "cell_type": "markdown", + "id": "190d3e7b", + "metadata": {}, + "source": [ + "## Define trace names\n", + "\n", + "Change the trace name with projects and users.\n", + "Reuse the compliance template and update traces accordingly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afd35a8c", + "metadata": {}, + "outputs": [], + "source": [ + "v.reports[\"insertion losses\"].traces = insertion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ad37c3d", + "metadata": {}, + "outputs": [], + "source": [ + "v.reports[\"return losses\"].traces = return_diff" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a818857f", + "metadata": {}, + "outputs": [], + "source": [ + "v.reports[\"common mode return losses\"].traces = return_comm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf122952", + "metadata": {}, + "outputs": [], + "source": [ + "v.reports[\"eye1\"].traces = eye_curve_tx\n", + "v.reports[\"eye3\"].traces = eye_curve_tx\n", + "v.reports[\"tdr from circuit\"].traces = tdr_probe_name\n", + "v.parameters[\"erl\"].trace_pins = [\n", + " [\n", + " \"X1.A5.PCIe_Gen4_RX1_P\",\n", + " \"X1.A6.PCIe_Gen4_RX1_N\",\n", + " \"U1.AR25.PCIe_Gen4_RX1_P\",\n", + " \"U1.AP25.PCIe_Gen4_RX1_N\",\n", + " ],\n", + " [7, 8, 18, 17],\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "fc29c55b", + "metadata": {}, + "source": [ + "## Generate PDF report\n", + "\n", + "Generate the reports and produce a PDF report.\n", + "\n", + "\n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df3e0087", + "metadata": {}, + "outputs": [], + "source": [ + "v.create_compliance_report()" + ] + }, + { + "cell_type": "markdown", + "id": "1aa864ec", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113f1c99", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c5e3484f", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8723f1f9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/coaxial_hfss_icepak.ipynb.txt b/version/dev/_sources/examples/electrothermal/coaxial_hfss_icepak.ipynb.txt new file mode 100644 index 00000000..3c192bc5 --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/coaxial_hfss_icepak.ipynb.txt @@ -0,0 +1,904 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "31af9d39", + "metadata": {}, + "source": [ + "# Coaxial\n", + "\n", + "This example shows how to create a project from scratch in HFSS and Icepak.\n", + "This includes creating a setup, solving it, and creating postprocessing outputs.\n", + "\n", + "Keywords: **Multiphysics**, **HFSS**, **Icepak**." + ] + }, + { + "cell_type": "markdown", + "id": "3a8c8c19", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac31560d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3eebe33", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.visualization.plot.pdf import AnsysReport" + ] + }, + { + "cell_type": "markdown", + "id": "8d745385", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69e88613", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "4b3e76bf", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7b08c54", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "3a4aab42", + "metadata": {}, + "source": [ + "## Launch AEDT and initialize HFSS\n", + "\n", + "Launch AEDT and initialize HFSS. If there is an active HFSS design, the ``hfss``\n", + "object is linked to it. Otherwise, a new design is created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e490e03d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = ansys.aedt.core.Hfss(\n", + " project=os.path.join(temp_folder.name, \"Icepak_HFSS_Coupling\"),\n", + " design=\"RF\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " solution_type=\"Modal\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2325729c", + "metadata": {}, + "source": [ + "## Define parameters\n", + "\n", + "Parameters can be instantiated by defining them as a key used for the application\n", + "instance as demonstrated in the following code. The prefix ``$`` is used to define\n", + "a project-wide scope for the parameter. Otherwise, the parameter scope is limited to\n", + "the current design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dca3a613", + "metadata": {}, + "outputs": [], + "source": [ + "hfss[\"$coax_dimension\"] = \"100mm\" # Project-wide scope.\n", + "udp = hfss.modeler.Position(0, 0, 0)\n", + "hfss[\"inner\"] = \"3mm\" # Local \"Design\" scope." + ] + }, + { + "cell_type": "markdown", + "id": "db7af45f", + "metadata": {}, + "source": [ + "## Create coaxial and cylinders\n", + "\n", + "Create a coaxial and three cylinders. You can apply parameters\n", + "directly using the `ansys.aedt.core.modeler.Primitives3D.Primitives3D.create_cylinder()`\n", + "method. You can assign a material directly to the object creation action.\n", + "Optionally, you can assign a material using the `assign_material()` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0b08679", + "metadata": {}, + "outputs": [], + "source": [ + "o1 = hfss.modeler.create_cylinder(\n", + " orientation=hfss.PLANE.ZX,\n", + " origin=udp,\n", + " radius=\"inner\",\n", + " height=\"$coax_dimension\",\n", + " num_sides=0,\n", + " name=\"inner\",\n", + ")\n", + "o2 = hfss.modeler.create_cylinder(\n", + " orientation=hfss.PLANE.ZX,\n", + " origin=udp,\n", + " radius=8,\n", + " height=\"$coax_dimension\",\n", + " num_sides=0,\n", + " name=\"teflon_based\",\n", + ")\n", + "o3 = hfss.modeler.create_cylinder(\n", + " orientation=hfss.PLANE.ZX,\n", + " origin=udp,\n", + " radius=10,\n", + " height=\"$coax_dimension\",\n", + " num_sides=0,\n", + " name=\"outer\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2071ad72", + "metadata": {}, + "source": [ + "## Assign colors\n", + "\n", + "Assign colors to each primitive." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d975a1c", + "metadata": {}, + "outputs": [], + "source": [ + "o1.color = (255, 0, 0)\n", + "o2.color = (0, 255, 0)\n", + "o3.color = (255, 0, 0)\n", + "o3.transparency = 0.8\n", + "hfss.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "0b9617f8", + "metadata": {}, + "source": [ + "## Assign materials\n", + "\n", + "Assign materials. You can assign materials either directly when creating the primitive,\n", + "which was done for ``id2``, or after the object is created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "322e4371", + "metadata": {}, + "outputs": [], + "source": [ + "o1.material_name = \"Copper\"\n", + "o3.material_name = \"Copper\"" + ] + }, + { + "cell_type": "markdown", + "id": "3ec5666e", + "metadata": {}, + "source": [ + "## Perform modeler operations\n", + "\n", + "Perform modeler operations. You can subtract, add, and perform other operations\n", + "using either the object ID or object name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50eeb6d4", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.subtract(o3, o2, True)\n", + "hfss.modeler.subtract(o2, o1, True)" + ] + }, + { + "cell_type": "markdown", + "id": "81afa8e5", + "metadata": {}, + "source": [ + "## Assign mesh operations\n", + "\n", + "Most mesh operations are accessible using the ``mesh`` property,\n", + "which is an instance of the ``ansys.aedt.core.modules.MeshIcepak.IcepakMesh`` class.\n", + "\n", + "This code shows how to use several common mesh operations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aef5a5cd", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.mesh.assign_initial_mesh_from_slider(level=6)\n", + "hfss.mesh.assign_model_resolution(assignment=[o1.name, o3.name], defeature_length=None)\n", + "hfss.mesh.assign_length_mesh(\n", + " assignment=o2.faces, inside_selection=False, maximum_length=1, maximum_elements=2000\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fea8a888", + "metadata": {}, + "source": [ + "## Create HFSS sources\n", + "\n", + "The RF power dissipated in the HFSS model acts as the thermal\n", + "source for in Icepak. The ``create_wave_port_between_objects()`` method\n", + "is used to assign the RF ports that inject RF power into the HFSS\n", + "model. If ``add_pec_cap=True``, then the method\n", + "creates a perfectly conducting (lossless) cap covering the port." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26653fce", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.wave_port(\n", + " assignment=\"inner\",\n", + " reference=\"outer\",\n", + " integration_line=1,\n", + " create_port_sheet=True,\n", + " create_pec_cap=True,\n", + " name=\"P1\",\n", + ")\n", + "\n", + "hfss.wave_port(\n", + " assignment=\"inner\",\n", + " reference=\"outer\",\n", + " integration_line=4,\n", + " create_pec_cap=True,\n", + " create_port_sheet=True,\n", + " name=\"P2\",\n", + ")\n", + "\n", + "port_names = hfss.get_all_sources()\n", + "hfss.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "aef5e1e2", + "metadata": {}, + "source": [ + "## Set up simulation\n", + "\n", + "Create a HFSS setup with default values. After its creation,\n", + "you can change values and update the setup. The ``update()`` method returns a Boolean\n", + "value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3446120", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.set_active_design(hfss.design_name)\n", + "setup = hfss.create_setup(\"MySetup\")\n", + "setup.props[\"Frequency\"] = \"1GHz\"\n", + "setup.props[\"BasisOrder\"] = 2\n", + "setup.props[\"MaximumPasses\"] = 1" + ] + }, + { + "cell_type": "markdown", + "id": "d0ad950e", + "metadata": {}, + "source": [ + "## Create frequency sweep\n", + "\n", + "The HFSS frequency sweep defines the RF frequency range over which the RF power is\n", + "injected into the structure." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "488f264a", + "metadata": {}, + "outputs": [], + "source": [ + "sweepname = hfss.create_linear_count_sweep(\n", + " setup=\"MySetup\",\n", + " units=\"GHz\",\n", + " start_frequency=0.8,\n", + " stop_frequency=1.2,\n", + " num_of_freq_points=401,\n", + " sweep_type=\"Interpolating\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "dbbd1f2a", + "metadata": {}, + "source": [ + "## Create Icepak model\n", + "\n", + "After an HFSS setup has been defined, the model can be lnked to an Icepak\n", + "design. The coupled physics analysis can then be run. The `FieldAnalysis3D.copy_solid_bodies_from()`\n", + "method imports a model from HFSS into Icepak, including all material definitions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae01b60c", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = ansys.aedt.core.Icepak(design=\"CalcTemp\", version=AEDT_VERSION)\n", + "ipk.copy_solid_bodies_from(hfss)" + ] + }, + { + "cell_type": "markdown", + "id": "e0e624bd", + "metadata": {}, + "source": [ + "## Link RF thermal source\n", + "\n", + "The RF loss in HFSS is used as the thermal source in Icepak." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "551b0139", + "metadata": {}, + "outputs": [], + "source": [ + "surfaceobj = [\"inner\", \"outer\"]\n", + "ipk.assign_em_losses(\n", + " design=hfss.design_name,\n", + " setup=\"MySetup\",\n", + " sweep=\"LastAdaptive\",\n", + " map_frequency=\"1GHz\",\n", + " surface_objects=surfaceobj,\n", + " parameters=[\"$coax_dimension\", \"inner\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bf82cb37", + "metadata": {}, + "source": [ + "## Set direction of gravity\n", + "\n", + "Set the direction of gravity for convection in Icepak. Gravity drives a temperature gradient\n", + "due to the dependence of gas density on temperature." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2952c222", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.edit_design_settings(hfss.GRAVITY.ZNeg)" + ] + }, + { + "cell_type": "markdown", + "id": "47377701", + "metadata": {}, + "source": [ + "## Set up Icepak Project\n", + "\n", + "The initial solution setup applies default values that can subsequently\n", + "be modified as shown in the following code.\n", + "The ``props`` property enables access to all solution settings.\n", + "\n", + "The ``update`` function applies the settings to the setup. The setup creation\n", + "process is identical for all tools." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07f516a0", + "metadata": {}, + "outputs": [], + "source": [ + "setup_ipk = ipk.create_setup(\"SetupIPK\")\n", + "setup_ipk.props[\"Convergence Criteria - Max Iterations\"] = 3" + ] + }, + { + "cell_type": "markdown", + "id": "3073158b", + "metadata": {}, + "source": [ + "### Access Icepak solution properties\n", + "\n", + "Setup properties are accessible through the ``props`` property as\n", + "an ordered dictionary. You can use the ``keys()`` method to retrieve all settings for\n", + "the setup.\n", + "\n", + "Find properties that contain the string ``\"Convergence\"`` and print the default values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36380a17", + "metadata": {}, + "outputs": [], + "source": [ + "conv_props = [k for k in setup_ipk.props.keys() if \"Convergence\" in k]\n", + "print(\"Here are some default setup properties:\")\n", + "for p in conv_props:\n", + " print('\"' + p + '\" -> ' + str(setup_ipk.props[p]))" + ] + }, + { + "cell_type": "markdown", + "id": "f07288c8", + "metadata": {}, + "source": [ + "### Edit or review mesh parameters\n", + "\n", + "Edit or review the mesh parameters. After a mesh is created, you can access\n", + "a mesh operation to edit or review parameter values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6324b043", + "metadata": {}, + "outputs": [], + "source": [ + "airbox = ipk.modeler.get_obj_id(\"Region\")\n", + "ipk.modeler[airbox].display_wireframe = True\n", + "airfaces = ipk.modeler.get_object_faces(airbox)\n", + "ipk.assign_openings(airfaces)" + ] + }, + { + "cell_type": "markdown", + "id": "9c845086", + "metadata": {}, + "source": [ + "Save the project and attach to the Icepak instance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d199c3c7", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "ipk = ansys.aedt.core.Icepak(version=AEDT_VERSION)\n", + "ipk.solution_type = ipk.SOLUTIONS.Icepak.SteadyTemperatureAndFlow\n", + "ipk.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "8fb8cc3a", + "metadata": {}, + "source": [ + "## Solve models\n", + "\n", + "Solve the Icepak and HFSS models." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92514ff5", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.setups[0].analyze(cores=NUM_CORES, tasks=NUM_CORES)\n", + "hfss.save_project()\n", + "hfss.modeler.fit_all()\n", + "hfss.setups[0].analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "d65b5ec9", + "metadata": {}, + "source": [ + "### Plot and export results\n", + "\n", + "Generate field plots in the HFSS project and export them as images." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f115dfd", + "metadata": {}, + "outputs": [], + "source": [ + "quantity_name = \"ComplexMag_H\"\n", + "intrinsic = {\"Freq\": hfss.setups[0].props[\"Frequency\"], \"Phase\": \"0deg\"}\n", + "surface_list = hfss.modeler.get_object_faces(\"outer\")\n", + "plot1 = hfss.post.create_fieldplot_surface(\n", + " assignment=surface_list,\n", + " quantity=quantity_name,\n", + " setup=hfss.nominal_adaptive,\n", + " intrinsics=intrinsic,\n", + ")\n", + "\n", + "hfss.post.plot_field_from_fieldplot(\n", + " plot1.name,\n", + " project_path=temp_folder.name,\n", + " mesh_plot=False,\n", + " image_format=\"jpg\",\n", + " view=\"isometric\",\n", + " show=False,\n", + " plot_cad_objs=False,\n", + " log_scale=False,\n", + " file_format=\"aedtplt\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "728f238e", + "metadata": {}, + "source": [ + "## Generate animation from field plots\n", + "\n", + "Generate an animation from field plots using PyVista." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b47bfb60", + "metadata": {}, + "outputs": [], + "source": [ + "start = time.time()\n", + "cutlist = [\"Global:XY\"]\n", + "phase_values = [str(i * 5) + \"deg\" for i in range(18)]\n", + "\n", + "animated = hfss.post.plot_animated_field(\n", + " quantity=\"Mag_E\",\n", + " assignment=cutlist,\n", + " plot_type=\"CutPlane\",\n", + " setup=hfss.nominal_adaptive,\n", + " intrinsics=intrinsic,\n", + " export_path=temp_folder.name,\n", + " variation_variable=\"Phase\",\n", + " variations=phase_values,\n", + " show=False,\n", + " export_gif=False,\n", + " log_scale=True,\n", + ")\n", + "animated.gif_file = os.path.join(temp_folder.name, \"animate.gif\")\n", + "\n", + "# Set off_screen to False to visualize the animation.\n", + "# animated.off_screen = False\n", + "\n", + "animated.animate()\n", + "\n", + "end_time = time.time() - start\n", + "print(\"Total Time\", end_time)" + ] + }, + { + "cell_type": "markdown", + "id": "45247083", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Create Icepak plots and export them as images using the same functions that\n", + "were used early. Only the quantity is different." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46b9adcd", + "metadata": {}, + "outputs": [], + "source": [ + "setup_name = ipk.existing_analysis_sweeps[0]\n", + "intrinsic = \"\"\n", + "surface_list = ipk.modeler.get_object_faces(\"inner\") + ipk.modeler.get_object_faces(\n", + " \"outer\"\n", + ")\n", + "plot5 = ipk.post.create_fieldplot_surface(surface_list, quantity=\"SurfTemperature\")\n", + "\n", + "hfss.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "d8bfa184", + "metadata": {}, + "source": [ + "Plot results using Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4dfb4fa4", + "metadata": {}, + "outputs": [], + "source": [ + "trace_names = hfss.get_traces_for_plot(category=\"S\")\n", + "context = [\"Domain:=\", \"Sweep\"]\n", + "families = [\"Freq:=\", [\"All\"]]\n", + "my_data = hfss.post.get_solution_data(expressions=trace_names)\n", + "my_data.plot(\n", + " trace_names,\n", + " formula=\"db20\",\n", + " x_label=\"Frequency (Ghz)\",\n", + " y_label=\"SParameters(dB)\",\n", + " title=\"Scattering Chart\",\n", + " snapshot_path=os.path.join(temp_folder.name, \"Touchstone_from_matplotlib.jpg\"),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e41885ee", + "metadata": {}, + "source": [ + "Create a PDF report summarizig results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6290840", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report = AnsysReport(\n", + " project_name=hfss.project_name, design_name=hfss.design_name, version=AEDT_VERSION\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "11e83cad", + "metadata": {}, + "source": [ + "Create the report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60ba0c63", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.create()" + ] + }, + { + "cell_type": "markdown", + "id": "8cd8ec3f", + "metadata": {}, + "source": [ + "Add a section for plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee2e3fd4", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_section()\n", + "pdf_report.add_chapter(\"HFSS Results\")\n", + "pdf_report.add_sub_chapter(\"Field plot\")\n", + "pdf_report.add_text(\"This section contains field plots of HFSS Coaxial.\")\n", + "pdf_report.add_image(\n", + " os.path.join(temp_folder.name, plot1.name + \".jpg\"), caption=\"Coaxial cable\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cfd268aa", + "metadata": {}, + "source": [ + "Add a page break and a subchapter for S Parameter results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa3b924d", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_page_break()\n", + "pdf_report.add_sub_chapter(\"S Parameters\")\n", + "pdf_report.add_chart(\n", + " x_values=my_data.intrinsics[\"Freq\"],\n", + " y_values=my_data.data_db20(),\n", + " x_caption=\"Freq\",\n", + " y_caption=trace_names[0],\n", + " title=\"S-Parameters\",\n", + ")\n", + "pdf_report.add_image(\n", + " path=os.path.join(temp_folder.name, \"Touchstone_from_matplotlib.jpg\"),\n", + " caption=\"Touchstone from Matplotlib\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f2b9c9fc", + "metadata": {}, + "source": [ + "Add a new section for Icepak results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41812c2a", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_section()\n", + "pdf_report.add_chapter(\"Icepak Results\")\n", + "pdf_report.add_sub_chapter(\"Temperature Plot\")\n", + "pdf_report.add_text(\"This section contains Multiphysics temperature plot.\")" + ] + }, + { + "cell_type": "markdown", + "id": "df5f81fc", + "metadata": {}, + "source": [ + "Add table of content and save the PDF." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c115849", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_toc()\n", + "pdf_report.save_pdf(file_path=temp_folder.name, file_name=\"AEDT_Results.pdf\")" + ] + }, + { + "cell_type": "markdown", + "id": "517587fd", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0763696f", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "11c519d1", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1bc00371", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/component_3d.ipynb.txt b/version/dev/_sources/examples/electrothermal/component_3d.ipynb.txt new file mode 100644 index 00000000..636fda5c --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/component_3d.ipynb.txt @@ -0,0 +1,595 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9317acdc", + "metadata": {}, + "source": [ + "# Thermal analysis with 3D components" + ] + }, + { + "cell_type": "markdown", + "id": "7deb54ba", + "metadata": {}, + "source": [ + "This example shows how to create a thermal analysis of an electronic package by\n", + "taking advantage of 3D components with advanced features added by PyAEDT.\n", + "\n", + "Keywords: **Icepak**, **3D components**, **mesh regions**, **monitor objects**." + ] + }, + { + "cell_type": "markdown", + "id": "c7b2e947", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f383074c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6602c9f0", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Icepak, downloads" + ] + }, + { + "cell_type": "markdown", + "id": "7ff06c7c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62d314cc", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "3c4df9bd", + "metadata": {}, + "source": [ + "## Create temporary directory and download files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83cff604", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "package_temp_name, qfp_temp_name = downloads.download_icepak_3d_component(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f1410bfc", + "metadata": {}, + "source": [ + "## Create heatsink\n", + "Create an empty project in non-graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "244c5a40", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = Icepak(\n", + " project=os.path.join(temp_folder.name, \"Heatsink.aedt\"),\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " close_on_exit=True,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0d3183e0", + "metadata": {}, + "source": [ + "Remove the air region, which is present by default. An air region is not needed as the heatsink\n", + "is to be exported as a 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e6b1b12", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler[\"Region\"].delete()" + ] + }, + { + "cell_type": "markdown", + "id": "9586371c", + "metadata": {}, + "source": [ + "Define the heatsink using multiple boxes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73f9a1ad", + "metadata": {}, + "outputs": [], + "source": [ + "hs_base = ipk.modeler.create_box(\n", + " origin=[0, 0, 0], sizes=[37.5, 37.5, 2], name=\"HS_Base\"\n", + ")\n", + "hs_base.material_name = \"Al-Extruded\"\n", + "hs_fin = ipk.modeler.create_box(origin=[0, 0, 2], sizes=[37.5, 1, 18], name=\"HS_Fin1\")\n", + "hs_fin.material_name = \"Al-Extruded\"\n", + "n_fins = 11\n", + "hs_fins = hs_fin.duplicate_along_line(vector=[0, 3.65, 0], clones=n_fins)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2572f9b", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.plot(show=False, output_file=os.path.join(temp_folder.name, \"Heatsink.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "09222069", + "metadata": {}, + "source": [ + "Define a mesh region around the heatsink." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f2b10de", + "metadata": {}, + "outputs": [], + "source": [ + "mesh_region = ipk.mesh.assign_mesh_region(\n", + " assignment=[hs_base.name, hs_fin.name] + hs_fins\n", + ")\n", + "mesh_region.manual_settings = True\n", + "mesh_region.settings[\"MaxElementSizeX\"] = \"5mm\"\n", + "mesh_region.settings[\"MaxElementSizeY\"] = \"5mm\"\n", + "mesh_region.settings[\"MaxElementSizeZ\"] = \"1mm\"\n", + "mesh_region.settings[\"MinElementsInGap\"] = 4\n", + "mesh_region.settings[\"MaxLevels\"] = 2\n", + "mesh_region.settings[\"BufferLayers\"] = 2\n", + "mesh_region.settings[\"EnableMLM\"] = True\n", + "mesh_region.settings[\"UniformMeshParametersType\"] = \"Average\"\n", + "mesh_region.update()" + ] + }, + { + "cell_type": "markdown", + "id": "eacf8a0a", + "metadata": {}, + "source": [ + "Assign monitor objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af12fdad", + "metadata": {}, + "outputs": [], + "source": [ + "hs_middle_fin = ipk.modeler.get_object_from_name(assignment=hs_fins[n_fins // 2])\n", + "point_monitor_position = [\n", + " 0.5 * (hs_base.bounding_box[i] + hs_base.bounding_box[i + 3]) for i in range(2)\n", + "] + [\n", + " hs_middle_fin.bounding_box[-1]\n", + "] # average x,y, top z\n", + "ipk.monitor.assign_point_monitor(\n", + " point_position=point_monitor_position,\n", + " monitor_quantity=[\"Temperature\", \"HeatFlux\"],\n", + " monitor_name=\"TopPoint\",\n", + ")\n", + "ipk.monitor.assign_face_monitor(\n", + " face_id=hs_base.bottom_face_z.id,\n", + " monitor_quantity=\"Temperature\",\n", + " monitor_name=\"Bottom\",\n", + ")\n", + "ipk.monitor.assign_point_monitor_in_object(\n", + " name=hs_middle_fin.name,\n", + " monitor_quantity=\"Temperature\",\n", + " monitor_name=\"MiddleFinCenter\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7ffc0cd6", + "metadata": {}, + "source": [ + "Export the heatsink 3D component to a ``\"componentLibrary\"`` folder.\n", + "The ``auxiliary_dict`` parameter is set to ``True`` to export the monitor objects\n", + "along with the A3DCOMP file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05a7830e", + "metadata": {}, + "outputs": [], + "source": [ + "os.mkdir(os.path.join(temp_folder.name, \"componentLibrary\"))\n", + "ipk.modeler.create_3dcomponent(\n", + " input_file=os.path.join(temp_folder.name, \"componentLibrary\", \"Heatsink.a3dcomp\"),\n", + " name=\"Heatsink\",\n", + " export_auxiliary=True,\n", + ")\n", + "ipk.close_project(save=False)" + ] + }, + { + "cell_type": "markdown", + "id": "71f872e0", + "metadata": {}, + "source": [ + "## Create QFP\n", + "Open the previously downloaded project containing a QPF." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "585535ca", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = Icepak(project=qfp_temp_name, version=AEDT_VERSION)\n", + "ipk.plot(show=False, output_file=os.path.join(temp_folder.name, \"QFP2.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "d0f0010d", + "metadata": {}, + "source": [ + "Create a dataset for power dissipation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76a83511", + "metadata": {}, + "outputs": [], + "source": [ + "x_datalist = [45, 53, 60, 70]\n", + "y_datalist = [0.5, 3, 6, 9]\n", + "ipk.create_dataset(\n", + " name=\"PowerDissipationDataset\",\n", + " x=x_datalist,\n", + " y=y_datalist,\n", + " is_project_dataset=False,\n", + " x_unit=\"cel\",\n", + " y_unit=\"W\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6a280dfa", + "metadata": {}, + "source": [ + "Assign a source power condition to the die." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17d5cab0", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.create_source_power(\n", + " face_id=\"DieSource\",\n", + " thermal_dependent_dataset=\"PowerDissipationDataset\",\n", + " source_name=\"DieSource\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "916484de", + "metadata": {}, + "source": [ + "Assign thickness to the die attach surface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65a99444", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assign_conducting_plate_with_thickness(\n", + " obj_plate=\"Die_Attach\",\n", + " shell_conduction=True,\n", + " thickness=\"0.05mm\",\n", + " solid_material=\"Epoxy Resin-Typical\",\n", + " boundary_name=\"Die_Attach\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "02f83bbe", + "metadata": {}, + "source": [ + "Assign monitor objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c51c128", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.monitor.assign_point_monitor_in_object(\n", + " name=\"QFP2_die\", monitor_quantity=\"Temperature\", monitor_name=\"DieCenter\"\n", + ")\n", + "ipk.monitor.assign_surface_monitor(\n", + " surface_name=\"Die_Attach\", monitor_quantity=\"Temperature\", monitor_name=\"DieAttach\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8fdfb01d", + "metadata": {}, + "source": [ + "Export the QFP 3D component in the ``\"componentLibrary\"`` folder and close the project.\n", + "Here the auxiliary dictionary allows exporting not only the monitor objects but also the dataset\n", + "used for the power source assignment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32fa936e", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler.create_3dcomponent(\n", + " input_file=os.path.join(temp_folder.name, \"componentLibrary\", \"QFP.a3dcomp\"),\n", + " name=\"QFP\",\n", + " export_auxiliary=True,\n", + " datasets=[\"PowerDissipationDataset\"],\n", + ")\n", + "ipk.release_desktop(close_projects=False, close_desktop=False)" + ] + }, + { + "cell_type": "markdown", + "id": "d87b34c6", + "metadata": {}, + "source": [ + "## Create complete electronic package\n", + "Download and open a project containing the electronic package." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cf92f48", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = Icepak(\n", + " project=package_temp_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + ")\n", + "ipk.plot(\n", + " assignment=[o for o in ipk.modeler.object_names if not o.startswith(\"DomainBox\")],\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"electronic_package_missing_obj.jpg\"),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "74ba392d", + "metadata": {}, + "source": [ + "The heatsink and the QFP are missing. They can be inserted as 3D components.\n", + "The auxiliary files are needed because the goal is to also import monitor objects and datasets." + ] + }, + { + "cell_type": "markdown", + "id": "47cb9558", + "metadata": {}, + "source": [ + "Create a coordinate system for the heatsink so that it is placed on top of the AGP." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8828c597", + "metadata": {}, + "outputs": [], + "source": [ + "agp = ipk.modeler.get_object_from_name(assignment=\"AGP_IDF\")\n", + "cs = ipk.modeler.create_coordinate_system(\n", + " origin=[agp.bounding_box[0], agp.bounding_box[1], agp.bounding_box[-1]],\n", + " name=\"HeatsinkCS\",\n", + " reference_cs=\"Global\",\n", + " x_pointing=[1, 0, 0],\n", + " y_pointing=[0, 1, 0],\n", + ")\n", + "heatsink_obj = ipk.modeler.insert_3d_component(\n", + " input_file=os.path.join(temp_folder.name, \"componentLibrary\", \"Heatsink.a3dcomp\"),\n", + " coordinate_system=\"HeatsinkCS\",\n", + " auxiliary_parameters=True,\n", + ")\n", + "\n", + "QFP2_obj = ipk.modeler.insert_3d_component(\n", + " input_file=os.path.join(temp_folder.name, \"componentLibrary\", \"QFP.a3dcomp\"),\n", + " coordinate_system=\"Global\",\n", + " auxiliary_parameters=True,\n", + ")\n", + "\n", + "ipk.plot(\n", + " assignment=[o for o in ipk.modeler.object_names if not o.startswith(\"DomainBox\")],\n", + " show=False,\n", + " plot_air_objects=False,\n", + " output_file=os.path.join(temp_folder.name, \"electronic_package.jpg\"),\n", + " force_opacity_value=0.5,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c25b26b9", + "metadata": {}, + "source": [ + "Create a coordinate system at the xmin, ymin, and zmin of the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "905a33e7", + "metadata": {}, + "outputs": [], + "source": [ + "bounding_box = ipk.modeler.get_model_bounding_box()\n", + "cs_pcb_assembly = ipk.modeler.create_coordinate_system(\n", + " origin=[bounding_box[0], bounding_box[1], bounding_box[2]],\n", + " name=\"PCB_Assembly\",\n", + " reference_cs=\"Global\",\n", + " x_pointing=[1, 0, 0],\n", + " y_pointing=[0, 1, 0],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "aeb6d5e3", + "metadata": {}, + "source": [ + "Export the entire assembly as a 3D component and close the project. First, the nested\n", + "hierarchy must be flattened because nested 3D components are currently not supported. Subsequently,\n", + "the whole package can be exported as a 3D component. The auxiliary dictionary is needed\n", + "to export monitor objects, datasets, and native components." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b51f8e62", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.flatten_3d_components()" + ] + }, + { + "cell_type": "markdown", + "id": "5afa81da", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2da40a5b", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "5e2e8a7a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4cfb7a7f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/components_csv.ipynb.txt b/version/dev/_sources/examples/electrothermal/components_csv.ipynb.txt new file mode 100644 index 00000000..0ca9642b --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/components_csv.ipynb.txt @@ -0,0 +1,492 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b867b694", + "metadata": {}, + "source": [ + "# PCB component definition from CSV file and model image exports" + ] + }, + { + "cell_type": "markdown", + "id": "8e083aed", + "metadata": {}, + "source": [ + "This example shows how to create different types of blocks and assign power\n", + "and material to them using a CSV input file\n", + "\n", + "Keywords: **Icepak**, **boundaries**, **PyVista**, **CSV**, **PCB**, **components**." + ] + }, + { + "cell_type": "markdown", + "id": "66eaa420", + "metadata": {}, + "source": [ + "## Perform imports and define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90c6a65c", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import os\n", + "import tempfile\n", + "import time\n", + "from pathlib import Path\n", + "\n", + "import ansys.aedt.core\n", + "import matplotlib as mpl\n", + "import numpy as np\n", + "import pyvista as pv\n", + "from IPython.display import Image\n", + "from matplotlib import cm\n", + "from matplotlib import pyplot as plt\n" + ] + }, + { + "cell_type": "markdown", + "id": "253b70be", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87e6d22a", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "d434feb4", + "metadata": {}, + "source": [ + "## Download and open project\n", + "\n", + "Download the project and open it in non-graphical mode, using a temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa7ace46", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "project_name = os.path.join(temp_folder.name, \"Icepak_CSV_Import.aedt\")\n", + "ipk = ansys.aedt.core.Icepak(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f27001d0", + "metadata": {}, + "source": [ + "Create the PCB as a simple block with lumped material properties." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e3f0bab", + "metadata": {}, + "outputs": [], + "source": [ + "board = ipk.modeler.create_box(\n", + " origin=[-30.48, -27.305, 0],\n", + " sizes=[146.685, 71.755, 0.4064],\n", + " name=\"board_outline\",\n", + " material=\"FR-4_Ref\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4df286f6", + "metadata": {}, + "source": [ + "## Create components from CSV file\n", + "\n", + "Components are represented as simple cubes with dimensions and properties specified in a CSV file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0416d2b0", + "metadata": {}, + "outputs": [], + "source": [ + "filename = ansys.aedt.core.downloads.download_file(\n", + " \"icepak\", \"blocks-list.csv\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8fe758c6", + "metadata": {}, + "source": [ + "The CSV file lists block properties:\n", + "\n", + "- Type (solid, network, hollow)\n", + "- Name\n", + "- Dtart point (xs, ys, zs) and end point (xd, yd, zd)\n", + "- Material properties (for solid blocks)\n", + "- Power assignment\n", + "- Resistances to the board and to the case (for network blocks)\n", + "- Whether to add a monitor point to the block (0 or 1)\n", + "\n", + "The following table does not show entire rows and dat. It provides only a sample.\n", + "\n", + "\n", + "| block_type | name | xs | ys | zs | xd | yd | zd | matname | power | Rjb | Rjc | Monitor_point |\n", + "|------------|------|--------|--------|------|-------|-------|------|------------------|-------|-----|-----|---------------|\n", + "| hollow | R8 | 31.75 | -20.32 | 0.40 | 15.24 | 2.54 | 2.54 | | 1 | | | 0 |\n", + "| solid | U1 | 16.55 | 10.20 | 0.40 | 10.16 | 20.32 | 5.08 | Ceramic_material | 0.2 | | | 1 |\n", + "| solid | U2 | -51 | 10.16 | 0.40 | 10.16 | 27.94 | 5.08 | Ceramic_material | 0.1 | | | 1 |\n", + "| network | C180 | 47.62 | 19.05 | 0.40 | 3.81 | 2.54 | 2.43 | | 1.13 | 2 | 3 | 0 |\n", + "| network | C10 | 65.40 | -1.27 | 0.40 | 3.81 | 2.54 | 2.43 | | 0.562 | 2 | 3 | 0 |\n", + "| network | C20 | 113.03 | -0.63 | 0.40 | 2.54 | 3.81 | 2.43 | | 0.445 | 2 | 3 | 0 |\n", + "\n", + "The following code loops over each line of the CSV file, creating solid blocks\n", + "and assigning boundary conditions.\n", + "\n", + "Every row of the CSV file has information on a particular block." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "022dcde4", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "with open(filename, \"r\") as csv_file:\n", + " csv_reader = csv.DictReader(csv_file)\n", + " for row in csv_reader:\n", + " origin = [\n", + " float(row[\"xs\"]),\n", + " float(row[\"ys\"]),\n", + " float(row[\"zs\"]),\n", + " ] # block starting point\n", + " dimensions = [\n", + " float(row[\"xd\"]),\n", + " float(row[\"yd\"]),\n", + " float(row[\"zd\"]),\n", + " ] # block lengths in 3 dimensions\n", + " block_name = row[\"name\"] # block name\n", + "\n", + " # Define material name\n", + " if row[\"matname\"]:\n", + " material_name = row[\"matname\"]\n", + " else:\n", + " material_name = \"copper\"\n", + "\n", + " # Creates the block with the given name, coordinates, material, and type\n", + " block = ipk.modeler.create_box(\n", + " origin=origin, sizes=dimensions, name=block_name, material=material_name\n", + " )\n", + "\n", + " # Assign boundary conditions\n", + " if row[\"block_type\"] == \"solid\":\n", + " ipk.assign_solid_block(\n", + " object_name=block_name,\n", + " power_assignment=row[\"power\"] + \"W\",\n", + " boundary_name=block_name,\n", + " )\n", + " elif row[\"block_type\"] == \"network\":\n", + " ipk.create_two_resistor_network_block(\n", + " object_name=block_name,\n", + " pcb=board.name,\n", + " power=row[\"power\"] + \"W\",\n", + " rjb=row[\"Rjb\"],\n", + " rjc=row[\"Rjc\"],\n", + " )\n", + " else:\n", + " ipk.modeler[block.name].solve_inside = False\n", + " ipk.assign_hollow_block(\n", + " object_name=block_name,\n", + " assignment_type=\"Total Power\",\n", + " assignment_value=row[\"power\"] + \"W\",\n", + " boundary_name=block_name,\n", + " )\n", + "\n", + " # Create temperature monitor points if assigned value is 1 in the last\n", + " # column of the CSV file\n", + " if row[\"Monitor_point\"] == \"1\":\n", + " ipk.monitor.assign_point_monitor_in_object(\n", + " name=row[\"name\"],\n", + " monitor_quantity=\"Temperature\",\n", + " monitor_name=row[\"name\"],\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "31e9c826", + "metadata": {}, + "source": [ + "## Calculate the power assigned to all components" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a4f7c04", + "metadata": {}, + "outputs": [], + "source": [ + "power_budget, total_power = ipk.post.power_budget(units=\"W\")" + ] + }, + { + "cell_type": "markdown", + "id": "97df1589", + "metadata": {}, + "source": [ + "## Plot model using AEDT\n", + "\n", + "Set the colormap to use. You can use the previously computed power budget to set the minimum and maximum values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90ae532c", + "metadata": {}, + "outputs": [], + "source": [ + "cmap = plt.get_cmap(\"plasma\")\n", + "norm = mpl.colors.Normalize(\n", + " vmin=min(power_budget.values()), vmax=max(power_budget.values())\n", + ")\n", + "scalarMap = cm.ScalarMappable(norm=norm, cmap=cmap)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5765687c", + "metadata": {}, + "outputs": [], + "source": [ + "# Color the objects depending\n", + "for obj in ipk.modeler.objects.values():\n", + " if obj.name in power_budget:\n", + " obj.color = [\n", + " int(i * 255) for i in scalarMap.to_rgba(power_budget[obj.name])[0:3]\n", + " ]\n", + " obj.transparency = 0\n", + " else:\n", + " obj.color = [0, 0, 0]\n", + " obj.transparency = 0.9" + ] + }, + { + "cell_type": "markdown", + "id": "7cf0ce51", + "metadata": {}, + "source": [ + "Export the model image by creating a list of all objects that excludes ``Region``.\n", + "This list is then passed to the `export_model_picture()` function.\n", + "This approach ensures that the exported image is fitted to the PCB and its components." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f270cb4", + "metadata": {}, + "outputs": [], + "source": [ + "obj_list_noregion = list(ipk.modeler.object_names)\n", + "obj_list_noregion.remove(\"Region\")\n", + "export_file = os.path.join(temp_folder.name, \"object_power_AEDTExport.jpg\")\n", + "ipk.post.export_model_picture(\n", + " export_file, selections=obj_list_noregion, width=1920, height=1080\n", + ")\n", + "Image(export_file)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02529239", + "metadata": {}, + "outputs": [], + "source": [ + "# ### Plot model using PyAEDT\n", + "#\n", + "# Initialize a PyVista plotter\n", + "plotter = pv.Plotter(off_screen=True, window_size=[2048, 1536])" + ] + }, + { + "cell_type": "markdown", + "id": "047e7702", + "metadata": {}, + "source": [ + "Export all models objects to OBJ files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa4dddf3", + "metadata": {}, + "outputs": [], + "source": [ + "f = ipk.post.export_model_obj(\n", + " export_path=temp_folder.name, export_as_single_objects=True, air_objects=False\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "98a8ae53", + "metadata": {}, + "source": [ + "Add objects to the PyVista plotter. These objects are either set to a black color or assigned scalar values,\n", + "allowing them to be visualized with a colormap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8198a8d8", + "metadata": {}, + "outputs": [], + "source": [ + "for file, color, opacity in f:\n", + " if color == (0, 0, 0):\n", + " plotter.add_mesh(mesh=pv.read(file), color=\"black\", opacity=opacity)\n", + " else:\n", + " mesh = pv.read(filename=file)\n", + " mesh[\"Power\"] = np.full(\n", + " shape=mesh.n_points, fill_value=power_budget[Path(file).stem]\n", + " )\n", + " plotter.add_mesh(mesh=mesh, scalars=\"Power\", cmap=\"viridis\", opacity=opacity)" + ] + }, + { + "cell_type": "markdown", + "id": "5a9d96d6", + "metadata": {}, + "source": [ + "Add a label to the object with the maximum temperature." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ef16039", + "metadata": {}, + "outputs": [], + "source": [ + "max_pow_obj = \"MP1\"\n", + "plotter.add_point_labels(\n", + " points=[ipk.modeler[max_pow_obj].top_face_z.center],\n", + " labels=[f\"{max_pow_obj}, {power_budget[max_pow_obj]}W\"],\n", + " point_size=20,\n", + " font_size=30,\n", + " text_color=\"red\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "94b9bb62", + "metadata": {}, + "source": [ + "Export the file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "606609ec", + "metadata": {}, + "outputs": [], + "source": [ + "export_file = os.path.join(temp_folder.name, \"object_power_pyVista.png\")\n", + "plotter.screenshot(filename=export_file, scale=1)\n", + "Image(export_file)" + ] + }, + { + "cell_type": "markdown", + "id": "a7a6f704", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abe62e6b", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "time.sleep(\n", + " 3\n", + ") # Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory." + ] + }, + { + "cell_type": "markdown", + "id": "5e9f0684", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c3c3a5e", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/ecad_import.ipynb.txt b/version/dev/_sources/examples/electrothermal/ecad_import.ipynb.txt new file mode 100644 index 00000000..0a19e0c6 --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/ecad_import.ipynb.txt @@ -0,0 +1,317 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7e841c1e", + "metadata": {}, + "source": [ + "# Import of a PCB and its components via IDF and EDB" + ] + }, + { + "cell_type": "markdown", + "id": "a57e49c5", + "metadata": {}, + "source": [ + "This example shows how to import a PCB and its components using IDF files (LDB and BDF).\n", + "You can also use a combination of EMN and EMP files in a similar way.\n", + "\n", + "Keywords: **Icepak**, **PCB**, **IDF**." + ] + }, + { + "cell_type": "markdown", + "id": "504d6538", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "399330d0", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1d1ec7b", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core import Hfss3dLayout, Icepak" + ] + }, + { + "cell_type": "markdown", + "id": "b9917a65", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5797e859", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "a2bae306", + "metadata": {}, + "source": [ + "## Open project\n", + "\n", + "Open an empty project in non-graphical mode, using a temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e90b71b2", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "\n", + "ipk = Icepak(\n", + " project=os.path.join(temp_folder.name, \"Icepak_ECAD_Import.aedt\"),\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "820d1deb", + "metadata": {}, + "source": [ + "## Import the IDF files\n", + "\n", + "Import the BDF and LDF files. Sample files are shown here.\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "You can import the IDF files with several filtering options, including caps, resistors,\n", + "inductors, power, specific power, and size.\n", + "There are also options for PCB creation, including number of layers, copper percentages, and layer sizes.\n", + "\n", + "This example uses the default values for the PCB.\n", + "The imported PCB (from the IDF files) are deleted later and replaced by a PCB that has the trace\n", + "information (from ECAD) for higher accuracy." + ] + }, + { + "cell_type": "markdown", + "id": "21f50b29", + "metadata": {}, + "source": [ + "Download ECAD and IDF files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30b8d8ef", + "metadata": {}, + "outputs": [], + "source": [ + "def_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"icepak/Icepak_ECAD_Import/A1_uprev.aedb\",\n", + " name=\"edb.def\",\n", + " destination=temp_folder.name,\n", + ")\n", + "board_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"icepak/Icepak_ECAD_Import/\", name=\"A1.bdf\", destination=temp_folder.name\n", + ")\n", + "library_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"icepak/Icepak_ECAD_Import/\", name=\"A1.ldf\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a09dc12a", + "metadata": {}, + "source": [ + "Import IDF file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcb4272d", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.import_idf(board_path=board_path)" + ] + }, + { + "cell_type": "markdown", + "id": "e61ef9b8", + "metadata": {}, + "source": [ + "Save the project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de4e6642", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "365140e5", + "metadata": {}, + "source": [ + "## Import ECAD\n", + "Add an HFSS 3D Layout design with the layout information of the PCB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed9e4479", + "metadata": {}, + "outputs": [], + "source": [ + "hfss3d_lo = Hfss3dLayout(project=def_path, version=AEDT_VERSION)\n", + "hfss3d_lo.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "ae055cfa", + "metadata": {}, + "source": [ + "Create a PCB component in Icepak linked to the HFSS 3D Layout project. The polygon ``\"poly_0\"``\n", + "is used as the outline of the PCB, and a dissipation of ``\"1W\"`` is applied to the PCB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4bd31d6", + "metadata": {}, + "outputs": [], + "source": [ + "project_file = hfss3d_lo.project_file\n", + "design_name = hfss3d_lo.design_name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca762413", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.create_pcb_from_3dlayout(\n", + " component_name=\"PCB_pyAEDT\",\n", + " project_name=project_file,\n", + " design_name=design_name,\n", + " extent_type=\"Polygon\",\n", + " outline_polygon=\"poly_0\",\n", + " power_in=1,\n", + " close_linked_project_after_import=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d99a7d83", + "metadata": {}, + "source": [ + "Delete the simplified PCB object coming from the IDF import." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0743f5bb", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler.delete_objects_containing(\"IDF_BoardOutline\", False)" + ] + }, + { + "cell_type": "markdown", + "id": "654e941a", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6631dd9", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1209a63a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "654dcbdc", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/electrothermal.ipynb.txt b/version/dev/_sources/examples/electrothermal/electrothermal.ipynb.txt new file mode 100644 index 00000000..ac3b10ed --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/electrothermal.ipynb.txt @@ -0,0 +1,540 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "005e9286", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "# Electrothermal analysis\n", + "\n", + "This example shows how to use the EDB for DC IR analysis and\n", + "electrothermal analysis. The EDB is loaded into SIwave for analysis and postprocessing.\n", + "In the end, an Icepak project is exported from SIwave.\n", + "\n", + "- Set up EDB:\n", + " - Assign package and heatsink model to components.\n", + " - Create voltage and current sources.\n", + " - Create SIwave DC analysis.\n", + " - Define cutout.\n", + "- Import EDB into SIwave:\n", + " - Analyze DC IR.\n", + " - Export Icepak project." + ] + }, + { + "cell_type": "markdown", + "id": "94f41f33", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "219523f9", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import sys\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4977e378", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core.downloads import download_file\n", + "from pyedb import Edb, Siwave" + ] + }, + { + "cell_type": "markdown", + "id": "08361324", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78913875", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = True # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "2321ff1b", + "metadata": {}, + "source": [ + "Check if AEDT is launched in graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5000012", + "metadata": {}, + "outputs": [], + "source": [ + "if not NG_MODE:\n", + " print(\"Warning: this example requires graphical mode enabled.\")\n", + " sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "d1aaf16c", + "metadata": {}, + "source": [ + "## Create temporary directory and download files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75f1d21a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "30f73737", + "metadata": {}, + "source": [ + "Download the example PCB data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cbd9ce1", + "metadata": {}, + "outputs": [], + "source": [ + "aedb = download_file(source=\"edb/ANSYS-HSD_V1.aedb\", destination=temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "721f7cd5", + "metadata": {}, + "source": [ + "## Create configuration file\n", + "\n", + "This example uses a configuration file to set up the layout for analysis.\n", + "Create an empty dictionary to host all configurations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af05dd5f", + "metadata": {}, + "outputs": [], + "source": [ + "cfg = dict()" + ] + }, + { + "cell_type": "markdown", + "id": "e8fd06f8", + "metadata": {}, + "source": [ + "## Add component thermal information and heatsink definition" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c88be9ce", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"package_definitions\"] = [\n", + " {\n", + " \"name\": \"package_1\",\n", + " \"component_definition\": \"SMTC-MECT-110-01-M-D-RA1_V\",\n", + " \"maximum_power\": 1,\n", + " \"therm_cond\": 1,\n", + " \"theta_jb\": 1,\n", + " \"theta_jc\": 1,\n", + " \"height\": \"2mm\",\n", + " \"heatsink\": {\n", + " \"fin_base_height\": \"2mm\",\n", + " \"fin_height\": \"4mm\",\n", + " \"fin_orientation\": \"x_oriented\",\n", + " \"fin_spacing\": \"1mm\",\n", + " \"fin_thickness\": \"1mm\",\n", + " },\n", + " \"apply_to_all\": False,\n", + " \"components\": [\"J5\"],\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "22fc1c46", + "metadata": {}, + "source": [ + "## Create pin groups\n", + "\n", + "Group all pins on the \"GND\" net on the ``J5`` component into one group.\n", + "Pin groups are assigned by net name using the ``net`` key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ecbe3dd", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"pin_groups\"] = [{\"name\": \"J5_GND\", \"reference_designator\": \"J5\", \"net\": \"GND\"}]" + ] + }, + { + "cell_type": "markdown", + "id": "9f77d133", + "metadata": {}, + "source": [ + "## Create current sources\n", + "\n", + "Create two current sources on the ``J5`` component.\n", + "A current source is placed between positive and negative terminals.\n", + "When the ``net`` keyword is used, all pins on the specified net are grouped into a\n", + "new pin group that is assigned as the positive terminal.\n", + "\n", + "Negative terminal can be assigned by pin group name by using the ``pin_group`` keyword.\n", + "The two current sources share the same ``J5_GND`` pin group as the negative terminal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7b0793e", + "metadata": {}, + "outputs": [], + "source": [ + "i_src_1 = {\n", + " \"name\": \"J5_VCCR\",\n", + " \"reference_designator\": \"J5\",\n", + " \"type\": \"current\",\n", + " \"magnitude\": 0.5,\n", + " \"positive_terminal\": {\"net\": \"SFPA_VCCR\"},\n", + " \"negative_terminal\": {\"pin_group\": \"J5_GND\"}, # Defined in \"pin_groups\" section.\n", + "}\n", + "i_src_2 = {\n", + " \"name\": \"J5_VCCT\",\n", + " \"reference_designator\": \"J5\",\n", + " \"type\": \"current\",\n", + " \"magnitude\": 0.5,\n", + " \"positive_terminal\": {\"net\": \"SFPA_VCCT\"},\n", + " \"negative_terminal\": {\"pin_group\": \"J5_GND\"}, # Defined in \"pin_groups\" section.\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "67ad4d7e", + "metadata": {}, + "source": [ + "## Create a voltage source\n", + "\n", + "Create a voltage source on the ``U4`` componebt between two nets using the ``net`` keyword." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b5a22c8", + "metadata": {}, + "outputs": [], + "source": [ + "v_src = {\n", + " \"name\": \"VSOURCE_5V\",\n", + " \"reference_designator\": \"U4\",\n", + " \"type\": \"voltage\",\n", + " \"magnitude\": 5,\n", + " \"positive_terminal\": {\"net\": \"5V\"},\n", + " \"negative_terminal\": {\"net\": \"GND\"},\n", + "}\n", + "\n", + "cfg[\"sources\"] = [v_src, i_src_1, i_src_2]" + ] + }, + { + "cell_type": "markdown", + "id": "125de3d2", + "metadata": {}, + "source": [ + "## Define cutout\n", + "\n", + "The following assignments define the region of the PCB to be cut out for analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4639f093", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"operations\"] = {\n", + " \"cutout\": {\n", + " \"signal_list\": [\"SFPA_VCCR\", \"SFPA_VCCT\", \"5V\"],\n", + " \"reference_list\": [\"GND\"],\n", + " \"extent_type\": \"Bounding\",\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "25ee413f", + "metadata": {}, + "source": [ + "## Create SIwave DC analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45546408", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"setups\"] = [\n", + " {\n", + " \"name\": \"siwave_dc\",\n", + " \"type\": \"siwave_dc\",\n", + " \"dc_slider_position\": 0,\n", + " \"dc_ir_settings\": {\"export_dc_thermal_data\": True},\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "0f53683b", + "metadata": {}, + "source": [ + "## Save configuration to a JSON file\n", + "\n", + "The configuration file can be saved in JSON format and applied to layout data using the EDB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3c6f1c5", + "metadata": {}, + "outputs": [], + "source": [ + "pi_json = os.path.join(temp_folder.name, \"pi.json\")\n", + "\n", + "with open(pi_json, \"w\") as f:\n", + " json.dump(cfg, f, indent=4, ensure_ascii=False)" + ] + }, + { + "cell_type": "markdown", + "id": "d78736b6", + "metadata": {}, + "source": [ + "## Load configuration into EDB\n", + "\n", + "Load the configuration from the JSON file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3abbddc", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp = Edb(aedb, edbversion=AEDT_VERSION)\n", + "edbapp.configuration.load(config_file=pi_json)\n", + "edbapp.configuration.run()\n", + "edbapp.save()\n", + "edbapp.close()\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "875c0920", + "metadata": {}, + "source": [ + "The configured EDB file is saved in the temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5755384d", + "metadata": {}, + "outputs": [], + "source": [ + "print(temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "31fe2145", + "metadata": {}, + "source": [ + "## Analyze in SIwave\n", + "\n", + "Load EDB into SIwave." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01ac5abe", + "metadata": {}, + "outputs": [], + "source": [ + "siwave = Siwave(specified_version=AEDT_VERSION)\n", + "time.sleep(10)\n", + "siwave.open_project(proj_path=aedb)\n", + "siwave.save_project(projectpath=temp_folder.name, projectName=\"ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "4c8a66cb", + "metadata": {}, + "source": [ + "## Analyze" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05f68fc6", + "metadata": {}, + "outputs": [], + "source": [ + "siwave.run_dc_simulation()" + ] + }, + { + "cell_type": "markdown", + "id": "cb2ca532", + "metadata": {}, + "source": [ + "## Export Icepak project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41129b15", + "metadata": {}, + "outputs": [], + "source": [ + "siwave.export_icepak_project(\n", + " os.path.join(temp_folder.name, \"from_siwave.aedt\"), \"siwave_dc\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b4d82c6b", + "metadata": {}, + "source": [ + "## Close SIWave project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e85e2731", + "metadata": {}, + "outputs": [], + "source": [ + "siwave.close_project()" + ] + }, + { + "cell_type": "markdown", + "id": "cc7a9da0", + "metadata": {}, + "source": [ + "## Shut down SIwave" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33efd5f7", + "metadata": {}, + "outputs": [], + "source": [ + "siwave.quit_application()" + ] + }, + { + "cell_type": "markdown", + "id": "e073dd93", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.dir``. If you've run this example as a Jupyter notbook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14f8de9d", + "metadata": {}, + "outputs": [], + "source": [ + "time.sleep(3)\n", + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/graphic_card.ipynb.txt b/version/dev/_sources/examples/electrothermal/graphic_card.ipynb.txt new file mode 100644 index 00000000..a2b675c8 --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/graphic_card.ipynb.txt @@ -0,0 +1,742 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f0eddfad", + "metadata": {}, + "source": [ + "# Graphic card thermal analysis" + ] + }, + { + "cell_type": "markdown", + "id": "500239f2", + "metadata": {}, + "source": [ + "This example shows how to use pyAEDT to create a graphic card setup in\n", + "Icepak and postprocess the results.\n", + "The example file is an Icepak project with a model that is already created and\n", + "has materials assigned.\n", + "\n", + "Keywords: **Icepak**, **boundary conditions**, **postprocessing**, **monitors**." + ] + }, + { + "cell_type": "markdown", + "id": "8e80cb81", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a898433a", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbab4e47", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import pandas as pd\n", + "from IPython.display import Image" + ] + }, + { + "cell_type": "markdown", + "id": "c159f2d1", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11370566", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Do not show the graphical user interface." + ] + }, + { + "cell_type": "markdown", + "id": "dfc1179d", + "metadata": {}, + "source": [ + "## Create temporary directory and download project\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75cd0375", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "project_temp_name = ansys.aedt.core.downloads.download_icepak(\n", + " destination=temp_folder.name\n", + ")\n", + "# ## Open project\n", + "#\n", + "# Open the project without the GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70534b91", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = ansys.aedt.core.Icepak(\n", + " project=project_temp_name,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "537e9671", + "metadata": {}, + "source": [ + "## Plot model and rotate\n", + "\n", + "Plot the model using the pyAEDT-PyVista integration and save the result to a file.\n", + "Rotate the model and plot the rotated model again." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c18800a", + "metadata": {}, + "outputs": [], + "source": [ + "plot1 = ipk.plot(\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"Graphics_card_1.jpg\"),\n", + " plot_air_objects=False,\n", + ")\n", + "\n", + "ipk.modeler.rotate(ipk.modeler.object_names, \"X\")\n", + "\n", + "plot2 = ipk.plot(\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"Graphics_card_2.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bf11e1f6", + "metadata": {}, + "source": [ + "## Define boundary conditions\n", + "\n", + "Create source blocks on the CPU and memories." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38f4dfdf", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.create_source_block(object_name=\"CPU\", input_power=\"25W\")\n", + "ipk.create_source_block(object_name=[\"MEMORY1\", \"MEMORY1_1\"], input_power=\"5W\")" + ] + }, + { + "cell_type": "markdown", + "id": "2e3d6b7e", + "metadata": {}, + "source": [ + "The air region object handler is used to specify the inlet (fixed velocity condition) and outlet\n", + "(fixed pressure condition) at x_max and x_min." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50cf7325", + "metadata": {}, + "outputs": [], + "source": [ + "region = ipk.modeler[\"Region\"]\n", + "ipk.assign_pressure_free_opening(\n", + " assignment=region.top_face_x.id, boundary_name=\"Outlet\"\n", + ")\n", + "ipk.assign_velocity_free_opening(\n", + " assignment=region.bottom_face_x.id,\n", + " boundary_name=\"Inlet\",\n", + " velocity=[\"1m_per_sec\", \"0m_per_sec\", \"0m_per_sec\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5a01b591", + "metadata": {}, + "source": [ + "## Assign mesh settings\n", + "\n", + "### Assign mesh region\n", + "Assign a mesh region around the heat sink and CPU." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f30584de", + "metadata": {}, + "outputs": [], + "source": [ + "mesh_region = ipk.mesh.assign_mesh_region(assignment=[\"HEAT_SINK\", \"CPU\"])" + ] + }, + { + "cell_type": "markdown", + "id": "be5b8c62", + "metadata": {}, + "source": [ + "Print the available settings for the mesh region" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c5bbc20", + "metadata": {}, + "outputs": [], + "source": [ + "mesh_region.settings" + ] + }, + { + "cell_type": "markdown", + "id": "0754d282", + "metadata": {}, + "source": [ + "Set the mesh region settings to manual and see newly available settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "803fbc2f", + "metadata": {}, + "outputs": [], + "source": [ + "mesh_region.manual_settings = True\n", + "mesh_region.settings" + ] + }, + { + "cell_type": "markdown", + "id": "ce299006", + "metadata": {}, + "source": [ + "Modify settings and update." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9fee53e", + "metadata": {}, + "outputs": [], + "source": [ + "mesh_region.settings[\"MaxElementSizeX\"] = \"2mm\"\n", + "mesh_region.settings[\"MaxElementSizeY\"] = \"2mm\"\n", + "mesh_region.settings[\"MaxElementSizeZ\"] = \"2mm\"\n", + "mesh_region.settings[\"EnableMLM\"] = True\n", + "mesh_region.settings[\"MaxLevels\"] = \"2\"\n", + "mesh_region.settings[\"MinElementsInGap\"] = 4\n", + "mesh_region.update()" + ] + }, + { + "cell_type": "markdown", + "id": "45d364f6", + "metadata": {}, + "source": [ + "Modify the slack of the subregion around the objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8db91b0b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "subregion = mesh_region.assignment\n", + "subregion.positive_x_padding = \"20mm\"\n", + "subregion.positive_y_padding = \"5mm\"\n", + "subregion.positive_z_padding = \"5mm\"\n", + "subregion.negative_x_padding = \"5mm\"\n", + "subregion.negative_y_padding = \"5mm\"\n", + "subregion.negative_z_padding = \"10mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "ecbc3e7a", + "metadata": {}, + "source": [ + "## Assign monitors\n", + "\n", + "Assign a temperature face monitor to the CPU face in contact with the heatsink." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6d85feb", + "metadata": {}, + "outputs": [], + "source": [ + "cpu = ipk.modeler[\"CPU\"]\n", + "m1 = ipk.monitor.assign_face_monitor(\n", + " face_id=cpu.top_face_z.id,\n", + " monitor_quantity=\"Temperature\",\n", + " monitor_name=\"TemperatureMonitor1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "85f2dd62", + "metadata": {}, + "source": [ + "Assign multiple speed point monitors downstream of the assembly." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46a22d53", + "metadata": {}, + "outputs": [], + "source": [ + "speed_monitors = []\n", + "for x_pos in range(0, 10, 2):\n", + " m = ipk.monitor.assign_point_monitor(\n", + " point_position=[f\"{x_pos}mm\", \"40mm\", \"15mm\"], monitor_quantity=\"Speed\"\n", + " )\n", + " speed_monitors.append(m)" + ] + }, + { + "cell_type": "markdown", + "id": "15468b23", + "metadata": {}, + "source": [ + "## Solve project\n", + "\n", + "Create a setup, modify solver settings, and run the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6e2581e", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = ipk.create_setup()\n", + "setup1.props[\"Flow Regime\"] = \"Turbulent\"\n", + "setup1.props[\"Convergence Criteria - Max Iterations\"] = 5\n", + "setup1.props[\"Linear Solver Type - Pressure\"] = \"flex\"\n", + "setup1.props[\"Linear Solver Type - Temperature\"] = \"flex\"\n", + "ipk.save_project()\n", + "ipk.analyze(setup=setup1.name, cores=NUM_CORES, tasks=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "ca8dd76a", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "### Perform quantitative postprocessing" + ] + }, + { + "cell_type": "markdown", + "id": "62c54dd4", + "metadata": {}, + "source": [ + "Get the point monitor data. A dictionary is returned with ``'Min'``, ``'Max'``, and ``'Mean'`` keys." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3bb1a620", + "metadata": {}, + "outputs": [], + "source": [ + "temperature_data = ipk.post.evaluate_monitor_quantity(\n", + " monitor=m1, quantity=\"Temperature\"\n", + ")\n", + "temperature_data" + ] + }, + { + "cell_type": "markdown", + "id": "fa67a19c", + "metadata": {}, + "source": [ + "It is also possible to get the data as a Pandas dataframe for advanced postprocessing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd5ff48b", + "metadata": {}, + "outputs": [], + "source": [ + "speed_fs = ipk.post.create_field_summary()\n", + "for m_name in speed_monitors:\n", + " speed_fs.add_calculation(\n", + " entity=\"Monitor\", geometry=\"Volume\", geometry_name=m_name, quantity=\"Speed\"\n", + " )\n", + "speed_data = speed_fs.get_field_summary_data(pandas_output=True)" + ] + }, + { + "cell_type": "markdown", + "id": "0fd80d8f", + "metadata": {}, + "source": [ + "All the data is now in a dataframe, making it easy to visualize and manipulate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45390184", + "metadata": {}, + "outputs": [], + "source": [ + "speed_data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "1bc41ec3", + "metadata": {}, + "source": [ + "The ``speed_data`` dataframe contains data from monitors, so it can be expanded with information\n", + "of their position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c23aa902", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(3):\n", + " direction = [\"X\", \"Y\", \"Z\"][i]\n", + " speed_data[\"Position\" + direction] = [\n", + " ipk.monitor.all_monitors[entity].location[i] for entity in speed_data[\"Entity\"]\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "607f62cc", + "metadata": {}, + "source": [ + "Plot the velocity profile at different X positions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcba6f42", + "metadata": {}, + "outputs": [], + "source": [ + "speed_data.plot(\n", + " x=\"PositionX\",\n", + " y=\"Mean\",\n", + " kind=\"line\",\n", + " marker=\"o\",\n", + " ylabel=speed_data.at[0, \"Quantity\"],\n", + " xlabel=f\"x [{ipk.modeler.model_units}]\",\n", + " grid=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5019bbd7", + "metadata": {}, + "source": [ + "Extract temperature data at those same locations (so the ``speed_monitors`` list is used)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9db69d95", + "metadata": {}, + "outputs": [], + "source": [ + "temperature_fs = ipk.post.create_field_summary()\n", + "for m_name in speed_monitors:\n", + " temperature_fs.add_calculation(\n", + " entity=\"Monitor\",\n", + " geometry=\"Volume\",\n", + " geometry_name=m_name,\n", + " quantity=\"Temperature\",\n", + " )\n", + "temperature_fs = temperature_fs.get_field_summary_data(pandas_output=True)\n", + "temperature_fs.head()" + ] + }, + { + "cell_type": "markdown", + "id": "66205562", + "metadata": {}, + "source": [ + "The two dataframes can be merged using the `pd.merge()` function. With the merge, suffixes are\n", + "added to the column names to differentiate between the columns from each original dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "115751b3", + "metadata": {}, + "outputs": [], + "source": [ + "merged_df = pd.merge(\n", + " temperature_fs, speed_data, on=\"Entity\", suffixes=(\"_temperature\", \"_speed\")\n", + ")\n", + "merged_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "2c2c3543", + "metadata": {}, + "source": [ + "The column names are renamed based on the ``Quantity`` column of the original dataframes.\n", + "Finally, only the ``'Entity'``, ``'Mean_temperature'``, and ``'Mean_speed'`` columns are selected and\n", + "assigned to the merged dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "629ec330", + "metadata": {}, + "outputs": [], + "source": [ + "temperature_quantity = temperature_fs[\"Quantity\"].iloc[0]\n", + "velocity_quantity = speed_data[\"Quantity\"].iloc[0]\n", + "merged_df.rename(\n", + " columns={\"Mean_temperature\": temperature_quantity, \"Mean_speed\": velocity_quantity},\n", + " inplace=True,\n", + ")\n", + "merged_df = merged_df[\n", + " [\n", + " \"Entity\",\n", + " temperature_quantity,\n", + " velocity_quantity,\n", + " \"PositionX\",\n", + " \"PositionY\",\n", + " \"PositionZ\",\n", + " ]\n", + "]\n", + "merged_df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "061d1f6f", + "metadata": {}, + "source": [ + "Compute the correlation coefficient between velocity and temperature from the merged dataframe\n", + "and plot a scatter plot to visualize their relationship." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16c93229", + "metadata": {}, + "outputs": [], + "source": [ + "correlation = merged_df[velocity_quantity].corr(merged_df[temperature_quantity])\n", + "ax = merged_df.plot.scatter(x=velocity_quantity, y=temperature_quantity)\n", + "ax.set_xlabel(velocity_quantity)\n", + "ax.set_ylabel(temperature_quantity)\n", + "ax.set_title(f\"Correlation between Temperature and Velocity: {correlation:.2f}\")" + ] + }, + { + "cell_type": "markdown", + "id": "d5bd0a7a", + "metadata": {}, + "source": [ + "The further away from the assembly, the faster and colder the air due to mixing.\n", + "Despite being extremely simple, this example demonstrates the potential of importing field\n", + "summary data into Pandas." + ] + }, + { + "cell_type": "markdown", + "id": "905da60a", + "metadata": {}, + "source": [ + "### Perform qualitative Postprocessing\n", + "Create a temperature plot on main components and export it to a PNG file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0dafa1f", + "metadata": {}, + "outputs": [], + "source": [ + "surflist = [i.id for i in ipk.modeler[\"CPU\"].faces]\n", + "surflist += [i.id for i in ipk.modeler[\"MEMORY1\"].faces]\n", + "surflist += [i.id for i in ipk.modeler[\"MEMORY1_1\"].faces]\n", + "plot3 = ipk.post.create_fieldplot_surface(\n", + " assignment=surflist, quantity=\"SurfTemperature\"\n", + ")\n", + "path = plot3.export_image(\n", + " full_path=os.path.join(temp_folder.name, \"temperature.png\"),\n", + " orientation=\"top\",\n", + " show_region=False,\n", + ")\n", + "Image(filename=path) # Display the image" + ] + }, + { + "cell_type": "markdown", + "id": "fdda79e9", + "metadata": {}, + "source": [ + "Use PyVista to display the temperature map." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9468fba", + "metadata": {}, + "outputs": [], + "source": [ + "plot4 = ipk.post.plot_field(\n", + " quantity=\"Temperature\",\n", + " assignment=[\n", + " \"SERIAL_PORT\",\n", + " \"MEMORY1\",\n", + " \"MEMORY1_1\",\n", + " \"CAPACITOR\",\n", + " \"CAPACITOR_1\",\n", + " \"KB\",\n", + " \"HEAT_SINK\",\n", + " \"CPU\",\n", + " \"ALPHA_MAIN_PCB\",\n", + " ],\n", + " plot_cad_objs=False,\n", + " show=False,\n", + " export_path=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2fd3ad5e", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89c8bfea", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "a89cfe4e", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8d941b7", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/icepak_circuit_hfss_coupling.ipynb.txt b/version/dev/_sources/examples/electrothermal/icepak_circuit_hfss_coupling.ipynb.txt new file mode 100644 index 00000000..58ab512f --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/icepak_circuit_hfss_coupling.ipynb.txt @@ -0,0 +1,675 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4394a71e", + "metadata": {}, + "source": [ + "# Circuit-HFSS-Icepak coupling workflow\n", + "\n", + "This example shows how to create a two-way coupling\n", + "between HFSS and Icepak.\n", + "\n", + "Consider a design where some components are simulated in\n", + "HFSS with a full 3D model, while others are simulated in Circuit as lumped elements.\n", + "The electrical simulation is done by placing the HFSS design into a Circuit design as\n", + "a subcomponent and connecting the lumped components to its ports.\n", + "\n", + "The purpose of the workflow is to perform a thermal simulation\n", + "of the Circuit-HFSS design, creating a two-way coupling with Icepak\n", + "that allows running multiple iterations. The losses from both designs\n", + "are accounted for.\n", + "- EM losses are evaluated by the HFSS solver and fed into Icepak via a direct link.\n", + "- Losses from the lumped components in the Circuit design are evaluated\n", + "analytically and must be manually set into the Icepak boundary.\n", + "\n", + "On the back of the coupling, temperature information\n", + "is handled differently for HFSS and Circuit.\n", + "\n", + "- For HFSS, a temperature map is exported from the Icepak design and used to create a\n", + "3D dataset. Then, the material properties in the HFSS design are updated based on this\n", + "dataset.\n", + "- For Circuit, the average temperature of the lumped components is extracted from the\n", + "Icepak design and used to update the temperature-dependent characteristics of the\n", + "lumped components in Circuit.\n", + "\n", + "The Circuit design in this example contains only a\n", + "resistor component, with temperature-dependent resistance\n", + "described by this formula: ``0.162*(1+0.004*(TempE-TempE0))``,\n", + "where TempE is the current temperature and TempE0 is the\n", + "ambient temperature. The HFSS design includes only a cylinder\n", + "with temperature-dependent material conductivity, defined by\n", + "a 2D dataset. The resistor and the cylinder have\n", + "matching resistances.\n", + "\n", + "Keywords: **Multiphysics**, **HFSS**, **Icepak**, **Circuit**." + ] + }, + { + "cell_type": "markdown", + "id": "5f323766", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48243d4b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f1392ab", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core as aedt" + ] + }, + { + "cell_type": "markdown", + "id": "45915ebd", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "807b085b", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "604d53d4", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13bbe73a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "3ffc7c78", + "metadata": {}, + "source": [ + "## Download and open project\n", + "\n", + "Download and open the project. Save it to the temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b55c340c", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = aedt.downloads.download_file(\n", + " \"circuit_hfss_icepak\", \"Circuit-HFSS-Icepak-workflow.aedtz\", temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1a97f96c", + "metadata": {}, + "source": [ + "## Launch AEDT and initialize HFSS\n", + "\n", + "Launch AEDT and initialize HFSS. If there is an active HFSS design, the ``hfss``\n", + "object is linked to it. Otherwise, a new design is created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68a4fdcd", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = aedt.Circuit(\n", + " project=project_name,\n", + " new_desktop=True,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7a770e05", + "metadata": {}, + "source": [ + "## Set variable names\n", + "\n", + "Set the name of the resistor in Circuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14bbc25f", + "metadata": {}, + "outputs": [], + "source": [ + "resistor_body_name = \"Circuit_Component\"" + ] + }, + { + "cell_type": "markdown", + "id": "c4959c35", + "metadata": {}, + "source": [ + "Set the name of the cylinder body in HFSS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "117eb564", + "metadata": {}, + "outputs": [], + "source": [ + "device3D_body_name = \"Device_3D\"" + ] + }, + { + "cell_type": "markdown", + "id": "e36e30cc", + "metadata": {}, + "source": [ + "## Get HFSS design\n", + "\n", + "Get the HFSS design and prepare the material for the thermal link." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16d392fc", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = aedt.Hfss(project=circuit.project_name)" + ] + }, + { + "cell_type": "markdown", + "id": "f2110772", + "metadata": {}, + "source": [ + "## Create a material\n", + "\n", + "Create a material to be used to set the temperature map on it.\n", + "The material is created by duplicating the material assigned to the cylinder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "533ba8a7", + "metadata": {}, + "outputs": [], + "source": [ + "material_name = hfss.modeler.objects_by_name[device3D_body_name].material_name\n", + "new_material_name = material_name + \"_dataset\"\n", + "new_material = hfss.materials.duplicate_material(\n", + " material=material_name, name=new_material_name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e167f167", + "metadata": {}, + "source": [ + "## Modify material properties\n", + "\n", + "Save the conductivity value. It is used later in the iterations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5db2b6c4", + "metadata": {}, + "outputs": [], + "source": [ + "old_conductivity = new_material.conductivity.value" + ] + }, + { + "cell_type": "markdown", + "id": "1ba082bc", + "metadata": {}, + "source": [ + "Assign the new material to the cylinder object in HFSS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3d57237", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.objects_by_name[device3D_body_name].material_name = new_material_name" + ] + }, + { + "cell_type": "markdown", + "id": "865413fc", + "metadata": {}, + "source": [ + "Because this material has a high conductivity, HFSS automatically deactivates ``solve_inside``.\n", + "It must be turned back on to evaluate the losses inside the cylinder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2fdd19e", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.objects_by_name[device3D_body_name].solve_inside = True" + ] + }, + { + "cell_type": "markdown", + "id": "38151f8c", + "metadata": {}, + "source": [ + "## Get Icepak design" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a4e944d", + "metadata": {}, + "outputs": [], + "source": [ + "icepak = aedt.Icepak(project=circuit.project_name)" + ] + }, + { + "cell_type": "markdown", + "id": "3a56f613", + "metadata": {}, + "source": [ + "## Set parameters for iterations\n", + "\n", + "Set the initial temperature to a value closer to the final one, to speed up the convergence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9176a727", + "metadata": {}, + "outputs": [], + "source": [ + "circuit[\"TempE\"] = \"300cel\"" + ] + }, + { + "cell_type": "markdown", + "id": "c5f192a9", + "metadata": {}, + "source": [ + "Set the maximum number of iterations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9b904f0", + "metadata": {}, + "outputs": [], + "source": [ + "max_iter = 2" + ] + }, + { + "cell_type": "markdown", + "id": "2ba56bca", + "metadata": {}, + "source": [ + "Set the residual convergence criteria to stop the iterations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49b0b02d", + "metadata": {}, + "outputs": [], + "source": [ + "temp_residual_limit = 0.02\n", + "loss_residual_limit = 0.02" + ] + }, + { + "cell_type": "markdown", + "id": "5e4afb9c", + "metadata": {}, + "source": [ + "This variable is to contain iteration statistics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab35b7ee", + "metadata": {}, + "outputs": [], + "source": [ + "stats = {}" + ] + }, + { + "cell_type": "markdown", + "id": "a0b96821", + "metadata": {}, + "source": [ + "## Start iterations\n", + "\n", + "Each ``for`` loop is a complete two-way iteration.\n", + "The code is thoroughly commented.\n", + "For a full understanding, read the inline comments carefully." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a9f30a0", + "metadata": {}, + "outputs": [], + "source": [ + "for cp_iter in range(1, max_iter + 1):\n", + " stats[cp_iter] = {}\n", + "\n", + " # Step 1: Solve the HFSS design.\n", + " #\n", + " # Solve the HFSS design.\n", + " hfss.analyze(cores=NUM_CORES)\n", + "\n", + " # Step 2: Refresh the dynamic link and solve the Circuit design.\n", + " #\n", + " # Find the HFSS subcomponent in Circuit.\n", + " # This information is required by the ``refresh_dynamic_link()`` and ``push_excitations()`` methods.\n", + " hfss_component_name = \"\"\n", + " hfss_instance_name = \"\"\n", + " for component in circuit.modeler.components.components.values():\n", + " if (\n", + " component.model_name is not None\n", + " and hfss.design_name in component.model_name\n", + " ):\n", + " hfss_component_name = component.model_name\n", + " hfss_instance_name = component.refdes\n", + " break\n", + " if not hfss_component_name or not hfss_instance_name:\n", + " raise \"Hfss component not found in Circuit design\"\n", + "\n", + " # Refresh the dynamic link.\n", + " circuit.modeler.schematic.refresh_dynamic_link(name=hfss_component_name)\n", + "\n", + " # Solve the Circuit design.\n", + " circuit.analyze()\n", + "\n", + " # Step 3: Push the excitations. (HFSS design results are scaled automatically.)\n", + " #\n", + " # Push the excitations.\n", + " circuit.push_excitations(instance=hfss_instance_name)\n", + "\n", + " # Step 4: Extract the resistor's power loss value from the Circuit design.\n", + " #\n", + " # Evaluate the power loss on the resistor.\n", + " r_losses = circuit.post.get_solution_data(\n", + " expressions=\"0.5*mag(I(I1)*V(V1))\"\n", + " ).data_magnitude()[0]\n", + "\n", + " # Save the losses in the stats.\n", + " stats[cp_iter][\"losses\"] = r_losses\n", + "\n", + " # Step 5: Set the resistor's power loss value in the Icepak design (block thermal condition)\n", + " #\n", + " # Find the solid block boundary in Icepak.\n", + " boundaries = icepak.boundaries\n", + " boundary = None\n", + " for bb in boundaries:\n", + " if bb.name == \"Block1\":\n", + " boundary = bb\n", + " break\n", + " if not boundary:\n", + " raise \"Block boundary not defined in Icepak design.\"\n", + "\n", + " # Set the resistor's power loss in the Block Boundary.\n", + " boundary.props[\"Total Power\"] = str(r_losses) + \"W\"\n", + "\n", + " # Step 6: Solve the Icepak design.\n", + " #\n", + " # Clear linked data. Otherwise, Icepak continues to run the simulation with the initial losses.\n", + " icepak.clear_linked_data()\n", + "\n", + " # Solve the Icepak design.\n", + " icepak.analyze(cores=NUM_CORES)\n", + "\n", + " # Step 7: Export the temperature map from the Icepak design and create a new 3D dataset with it.\n", + " #\n", + " # Export the temperature map to a file.\n", + " fld_filename = os.path.join(\n", + " icepak.working_directory, f\"temperature_map_{cp_iter}.fld\"\n", + " )\n", + " icepak.post.export_field_file(\n", + " quantity=\"Temp\",\n", + " output_file=fld_filename,\n", + " assignment=\"AllObjects\",\n", + " objects_type=\"Vol\",\n", + " )\n", + "\n", + " # Convert the FLD file into a dataset tab file compatible with the dataset import.\n", + " # The existing header lines must be removed and replaced with a single header line\n", + " # containing the value unit.\n", + " with open(fld_filename, \"r\") as f:\n", + " lines = f.readlines()\n", + "\n", + " _ = lines.pop(0)\n", + " _ = lines.pop(0)\n", + " lines.insert(0, '\"X\" \"Y\" \"Z\" \"cel\"\\n')\n", + "\n", + " basename, _ = os.path.splitext(fld_filename)\n", + " tab_filename = basename + \"_dataset.tab\"\n", + "\n", + " with open(tab_filename, \"w\") as f:\n", + " f.writelines(lines)\n", + "\n", + " # Import the 3D dataset.\n", + " dataset_name = f\"temp_map_step_{cp_iter}\"\n", + " hfss.import_dataset3d(\n", + " input_file=tab_filename, name=dataset_name, is_project_dataset=True\n", + " )\n", + "\n", + " # Step 8: Update material properties in the HFSS design based on the new dataset.\n", + " #\n", + " # Set the new conductivity value.\n", + " new_material.conductivity.value = (\n", + " f\"{old_conductivity}*Pwl($TempDepCond,clp(${dataset_name},X,Y,Z))\"\n", + " )\n", + "\n", + " # Switch off the thermal modifier of the material, if any.\n", + " new_material.conductivity.thermalmodifier = None\n", + "\n", + " # Step 9: Extract the average temperature of the resistor from the Icepak design.\n", + " #\n", + " # Get the mean temperature value on the high-resistivity object.\n", + " mean_temp = icepak.post.get_scalar_field_value(\n", + " quantity=\"Temp\", scalar_function=\"Mean\", object_name=resistor_body_name\n", + " )\n", + "\n", + " # Save the temperature in the iteration statistics.\n", + " stats[cp_iter][\"temp\"] = mean_temp\n", + "\n", + " # Step 10: Update the resistance value in the Circuit design.\n", + " #\n", + " # Set this temperature in Circuit in the ``TempE`` variable.\n", + " circuit[\"TempE\"] = f\"{mean_temp}cel\"\n", + "\n", + " # Save the project\n", + " circuit.save_project()\n", + "\n", + " # Check the convergence of the iteration\n", + " #\n", + " # Evaluate the relative residuals on temperature and losses.\n", + " # If the residuals are smaller than the threshold, set the convergence flag to ``True```.\n", + " # Residuals are calculated starting from the second iteration.\n", + " converged = False\n", + " stats[cp_iter][\"converged\"] = converged\n", + " if cp_iter > 1:\n", + " delta_temp = abs(stats[cp_iter][\"temp\"] - stats[cp_iter - 1][\"temp\"]) / abs(\n", + " stats[cp_iter - 1][\"temp\"]\n", + " )\n", + " delta_losses = abs(\n", + " stats[cp_iter][\"losses\"] - stats[cp_iter - 1][\"losses\"]\n", + " ) / abs(stats[cp_iter - 1][\"losses\"])\n", + " if delta_temp <= temp_residual_limit and delta_losses <= loss_residual_limit:\n", + " converged = True\n", + " stats[cp_iter][\"converged\"] = converged\n", + " else:\n", + " delta_temp = None\n", + " delta_losses = None\n", + "\n", + " # Save the relative residuals in the iteration stats.\n", + " stats[cp_iter][\"delta_temp\"] = delta_temp\n", + " stats[cp_iter][\"delta_losses\"] = delta_losses\n", + "\n", + " # Exit from the loop if the convergence is reached.\n", + " if converged:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "id": "5ee759aa", + "metadata": {}, + "source": [ + "## Print overall statistics\n", + "\n", + "Print the overall statistics for the multiphysics loop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "166da480", + "metadata": {}, + "outputs": [], + "source": [ + "for i in stats:\n", + " txt = \"yes\" if stats[i][\"converged\"] else \"no\"\n", + " delta_temp = (\n", + " f\"{stats[i]['delta_temp']:.4f}\"\n", + " if stats[i][\"delta_temp\"] is not None\n", + " else \"None\"\n", + " )\n", + " delta_losses = (\n", + " f\"{stats[i]['delta_losses']:.4f}\"\n", + " if stats[i][\"delta_losses\"] is not None\n", + " else \"None\"\n", + " )\n", + " print(\n", + " f\"Step {i}: temp={stats[i]['temp']:.3f}, losses={stats[i]['losses']:.3f}, \"\n", + " f\"delta_temp={delta_temp}, delta_losses={delta_losses}, \"\n", + " f\"converged={txt}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "e492f1c3", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "decf81b5", + "metadata": {}, + "outputs": [], + "source": [ + "icepak.save_project()\n", + "icepak.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "5bf62b9f", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97d7bf10", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/electrothermal/index.rst.txt b/version/dev/_sources/examples/electrothermal/index.rst.txt new file mode 100644 index 00000000..b6322b74 --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/index.rst.txt @@ -0,0 +1,146 @@ +Electrothermal +~~~~~~~~~~~~~~ + +These examples use PyAEDT to show electrothermal capabilities of AEDT + +.. grid:: 2 + + .. grid-item-card:: PCB component definition from CSV file and model image exports + :padding: 2 2 2 2 + :link: components_csv + :link-type: doc + + .. image:: _static/icepak_csv.png + :alt: Icepak CSV + :width: 250px + :height: 200px + :align: center + + This example shows how to create different types of blocks and assign power and material to them using a CSV input file. + + + .. grid-item-card:: Import of a PCB and its components via IDF and EDB + :padding: 2 2 2 2 + :link: ecad_import + :link-type: doc + + .. image:: _static/ecad.png + :alt: Icepak ECAD + :width: 250px + :height: 200px + :align: center + + This example shows how to import a PCB and its components using IDF files (LDB and BDF). + You can also use a combination of EMN and EMP files in a similar way. + + + .. grid-item-card:: Thermal analysis with 3D components + :padding: 2 2 2 2 + :link: component_3d + :link-type: doc + + .. image:: _static/component.png + :alt: Thermal component + :width: 250px + :height: 200px + :align: center + + This example shows how to create a thermal analysis of an electronic package by taking advantage of 3D components with advanced features added by PyAEDT. + + + .. grid-item-card:: Graphic card thermal analysis + :padding: 2 2 2 2 + :link: graphic_card + :link-type: doc + + .. image:: _static/graphic.png + :alt: Graphic card + :width: 250px + :height: 200px + :align: center + + This example shows how to use pyAEDT to create a graphic card setup in Icepak and postprocess the results. + The example file is an Icepak project with a model that is already created and has materials assigned. + + + .. grid-item-card:: Coaxial + :padding: 2 2 2 2 + :link: coaxial_hfss_icepak + :link-type: doc + + .. image:: _static/coaxial.png + :alt: Coaxial + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project from scratch in HFSS and Icepak. + + + .. grid-item-card:: Setup from Sherlock inputs + :padding: 2 2 2 2 + :link: sherlock + :link-type: doc + + .. image:: _static/sherlock.png + :alt: Sherlock PCB + :width: 250px + :height: 200px + :align: center + + This example shows how to create an Icepak project from Sherlock files (STEP and CSV) and an AEDB board. + + .. grid-item-card:: Circuit-HFSS-Icepak coupling workflow + :padding: 2 2 2 2 + :link: icepak_circuit_hfss_coupling + :link-type: doc + + .. image:: _static/ring.png + :alt: Ring + :width: 250px + :height: 200px + :align: center + + This example shows how to create a two-way coupling between HFSS and Icepak. + + + .. grid-item-card:: Electrothermal analysis + :padding: 2 2 2 2 + :link: electrothermal + :link-type: doc + + .. image:: _static/electrothermal.png + :alt: Electrothermal + :width: 250px + :height: 200px + :align: center + + This example shows how to use the EDB for DC IR analysis and electrothermal analysis. + The EDB is loaded into SIwave for analysis and postprocessing. + In the end, an Icepak project is exported from SIwave. + + + .. grid-item-card:: Maxwell 3D-Icepak electrothermal analysis + :padding: 2 2 2 2 + :link: ../low_frequency/multiphysics/maxwell_icepak + :link-type: doc + + .. image:: ../low_frequency/multiphysics/_static/charging.png + :alt: Charging + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a simple Maxwell design consisting of a coil and a ferrite core. + +.. toctree:: + :hidden: + + components_csv + ecad_import + graphic_card + coaxial_hfss_icepak + sherlock + icepak_circuit_hfss_coupling + electrothermal + ../low_frequency/multiphysics/maxwell_icepak diff --git a/version/dev/_sources/examples/electrothermal/sherlock.ipynb.txt b/version/dev/_sources/examples/electrothermal/sherlock.ipynb.txt new file mode 100644 index 00000000..c46a2345 --- /dev/null +++ b/version/dev/_sources/examples/electrothermal/sherlock.ipynb.txt @@ -0,0 +1,515 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a64167bb", + "metadata": {}, + "source": [ + "# Setup from Sherlock inputs" + ] + }, + { + "cell_type": "markdown", + "id": "1946c3be", + "metadata": {}, + "source": [ + "This example shows how to create an Icepak project from Sherlock\n", + "files (STEP and CSV) and an AEDB board.\n", + "\n", + "Keywords: **Icepak**, **Sherlock**." + ] + }, + { + "cell_type": "markdown", + "id": "105239cb", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6a59965", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "ad2c69d1", + "metadata": {}, + "source": [ + "Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b536dfc", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "b9f13c84", + "metadata": {}, + "source": [ + "## Set paths and define input files and variables\n", + "\n", + "Set paths." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0851737c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "input_dir = ansys.aedt.core.downloads.download_sherlock(destination=temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "b87f4105", + "metadata": {}, + "source": [ + "Define input files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf62e4b4", + "metadata": {}, + "outputs": [], + "source": [ + "material_name = \"MaterialExport.csv\"\n", + "component_properties = \"TutorialBoardPartsList.csv\"\n", + "component_step = \"TutorialBoard.stp\"\n", + "aedt_odb_project = \"SherlockTutorial.aedt\"" + ] + }, + { + "cell_type": "markdown", + "id": "aab7dce5", + "metadata": {}, + "source": [ + "Define variables that are needed later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0462e0de", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_odb_design_name = \"PCB\"\n", + "outline_polygon_name = \"poly_14188\"" + ] + }, + { + "cell_type": "markdown", + "id": "e2956a04", + "metadata": {}, + "source": [ + "Define input files with paths." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87ad0d92", + "metadata": {}, + "outputs": [], + "source": [ + "material_list = os.path.join(input_dir, material_name)\n", + "component_list = os.path.join(input_dir, component_properties)\n", + "validation = os.path.join(temp_folder.name, \"validation.log\")\n", + "file_path = os.path.join(input_dir, component_step)\n", + "project_name = os.path.join(temp_folder.name, component_step[:-3] + \"aedt\")" + ] + }, + { + "cell_type": "markdown", + "id": "d8ae2fff", + "metadata": {}, + "source": [ + "## Create Icepak model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b224456", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = ansys.aedt.core.Icepak(\n", + " project=project_name, version=AEDT_VERSION, non_graphical=NG_MODE\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f484ee16", + "metadata": {}, + "source": [ + "Disable autosave to speed up the import." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5be58b0", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.autosave_disable()" + ] + }, + { + "cell_type": "markdown", + "id": "b3eeb745", + "metadata": {}, + "source": [ + "Import a PCB from an AEDB file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58a739b7", + "metadata": {}, + "outputs": [], + "source": [ + "odb_path = os.path.join(input_dir, aedt_odb_project)\n", + "ipk.create_pcb_from_3dlayout(\n", + " component_name=\"Board\", project_name=odb_path, design_name=aedt_odb_design_name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c7c9bb7b", + "metadata": {}, + "source": [ + "Create an offset coordinate system to match ODB++ with the Sherlock STEP file.\n", + "The thickness is computed from the ``\"Board\"`` component. (``\"Board1\"`` is the\n", + "instance name of the ``\"Board\"`` native component and is used to offset the coordinate system.)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63ea2dc3", + "metadata": {}, + "outputs": [], + "source": [ + "bb = ipk.modeler.user_defined_components[\"Board1\"].bounding_box\n", + "stackup_thickness = bb[-1] - bb[2]\n", + "ipk.modeler.create_coordinate_system(\n", + " origin=[0, 0, stackup_thickness / 2], mode=\"view\", view=\"XY\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9aeda074", + "metadata": {}, + "source": [ + "Import the board components from an MCAD file and remove the PCB object as it is already\n", + "imported with the ECAD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2a45d5d", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler.import_3d_cad(file_path, refresh_all_ids=False)\n", + "ipk.modeler.delete_objects_containing(\"pcb\", False)" + ] + }, + { + "cell_type": "markdown", + "id": "467ea8a7", + "metadata": {}, + "source": [ + "Modify the air region. Padding values are passed in this order: [+X, -X, +Y, -Y, +Z, -Z]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1df47205", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.mesh.global_mesh_region.global_region.padding_values = [20, 20, 20, 20, 300, 300]" + ] + }, + { + "cell_type": "markdown", + "id": "40936cdb", + "metadata": {}, + "source": [ + "## Assign materials and power dissipation conditions from Sherlock\n", + "\n", + "Use the Sherlock file to assign materials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c0d517a", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assignmaterial_from_sherlock_files(\n", + " component_file=component_list, material_file=material_list\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f56069f0", + "metadata": {}, + "source": [ + "Delete objects with no material assignments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56fb8160", + "metadata": {}, + "outputs": [], + "source": [ + "no_material_objs = ipk.modeler.get_objects_by_material(material=\"\")\n", + "ipk.modeler.delete(assignment=no_material_objs)\n", + "ipk.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "d0574ccd", + "metadata": {}, + "source": [ + "Assign power blocks from the Sherlock file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc680741", + "metadata": {}, + "outputs": [], + "source": [ + "total_power = ipk.assign_block_from_sherlock_file(csv_name=component_list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f206912", + "metadata": {}, + "outputs": [], + "source": [ + "# ## Assign openings\n", + "#\n", + "# Assign opening boundary condition to all the faces of the region.\n", + "ipk.assign_openings(ipk.modeler.get_object_faces(\"Region\"))" + ] + }, + { + "cell_type": "markdown", + "id": "96c9d09b", + "metadata": {}, + "source": [ + "## Create simulation setup\n", + "### Set global mesh settings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "379e1ab6", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "ipk.globalMeshSettings(\n", + " 3,\n", + " gap_min_elements=\"1\",\n", + " noOgrids=True,\n", + " MLM_en=True,\n", + " MLM_Type=\"2D\",\n", + " edge_min_elements=\"2\",\n", + " object=\"Region\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bc4dea32", + "metadata": {}, + "source": [ + "### Add postprocessing object\n", + "Create the point monitor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c6decf7", + "metadata": {}, + "outputs": [], + "source": [ + "point1 = ipk.monitor.assign_point_monitor(\n", + " point_position=ipk.modeler[\"COMP_U10\"].top_face_z.center, monitor_name=\"Point1\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "11bf2434", + "metadata": {}, + "source": [ + "Create a line for reporting after the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86a0d517", + "metadata": {}, + "outputs": [], + "source": [ + "line = ipk.modeler.create_polyline(\n", + " points=[\n", + " ipk.modeler[\"COMP_U10\"].top_face_z.vertices[0].position,\n", + " ipk.modeler[\"COMP_U10\"].top_face_z.vertices[2].position,\n", + " ],\n", + " non_model=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d2697489", + "metadata": {}, + "source": [ + "### Solve\n", + "To solve quickly, the maximum iterations are set to 20. For better accuracy, you\n", + "can increase the maximum to at least 100." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92c3e777", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = ipk.create_setup()\n", + "setup1.props[\"Solution Initialization - Y Velocity\"] = \"1m_per_sec\"\n", + "setup1.props[\"Radiation Model\"] = \"Discrete Ordinates Model\"\n", + "setup1.props[\"Include Gravity\"] = True\n", + "setup1.props[\"Secondary Gradient\"] = True\n", + "setup1.props[\"Convergence Criteria - Max Iterations\"] = 100" + ] + }, + { + "cell_type": "markdown", + "id": "bd0c16dd", + "metadata": {}, + "source": [ + "Check for intersections using validation and fix them by\n", + "assigning priorities." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0fe55ec", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assign_priority_on_intersections()" + ] + }, + { + "cell_type": "markdown", + "id": "99348137", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f16cba1", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b0aa876b", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cde9857f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/array.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/array.ipynb.txt new file mode 100644 index 00000000..19af3935 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/array.ipynb.txt @@ -0,0 +1,486 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "aec83d74", + "metadata": {}, + "source": [ + "# Component antenna array" + ] + }, + { + "cell_type": "markdown", + "id": "cdc2bc0d", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create an example using a 3D component file. It sets\n", + "up the analysis, solves it, and uses postprocessing functions to create plots using Matplotlib and\n", + "PyVista without opening the HFSS user interface. This example runs only on Windows using CPython.\n", + "\n", + "Keywords: **HFSS**, **antenna array**, **3D components**, **far field**." + ] + }, + { + "cell_type": "markdown", + "id": "168736c9", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33996244", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4e45dfa", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.visualization.advanced.farfield_visualization import \\\n", + " FfdSolutionData" + ] + }, + { + "cell_type": "markdown", + "id": "2450e15f", + "metadata": {}, + "source": [ + "Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64967092", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "3bc12373", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "255e37d8", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "66f789cf", + "metadata": {}, + "source": [ + "## Download 3D component\n", + "Download the 3D component that is needed to run the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06f9e978", + "metadata": {}, + "outputs": [], + "source": [ + "example_path = ansys.aedt.core.downloads.download_3dcomponent(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6d1f4f67", + "metadata": {}, + "source": [ + "## Launch HFSS and open project\n", + "\n", + "Launch HFSS and open the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b88a2e74", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"array.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " design=\"Array_Simple\",\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "\n", + "print(\"Project name \" + project_name)" + ] + }, + { + "cell_type": "markdown", + "id": "7d9d0b70", + "metadata": {}, + "source": [ + "## Read array definition\n", + "\n", + "Read array definition from the JSON file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5974188", + "metadata": {}, + "outputs": [], + "source": [ + "dict_in = ansys.aedt.core.general_methods.read_json(\n", + " os.path.join(example_path, \"array_simple.json\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2e5697d5", + "metadata": {}, + "source": [ + "## Define 3D component\n", + "\n", + "Define the 3D component cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64660865", + "metadata": {}, + "outputs": [], + "source": [ + "dict_in[\"Circ_Patch_5GHz1\"] = os.path.join(example_path, \"Circ_Patch_5GHz.a3dcomp\")" + ] + }, + { + "cell_type": "markdown", + "id": "28a63204", + "metadata": {}, + "source": [ + "## Add 3D component array\n", + "\n", + "A 3D component array is created from the previous dictionary.\n", + "If a 3D component is not available in the design, it is loaded\n", + "into the dictionary from the path that you specify. The following\n", + "code edits the dictionary to point to the location of the A3DCOMP file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc7bc420", + "metadata": {}, + "outputs": [], + "source": [ + "array = hfss.add_3d_component_array_from_json(dict_in)" + ] + }, + { + "cell_type": "markdown", + "id": "3fa410a5", + "metadata": {}, + "source": [ + "## Modify cells\n", + "\n", + "Make the center element passive and rotate the corner elements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99662c11", + "metadata": {}, + "outputs": [], + "source": [ + "array.cells[1][1].is_active = False\n", + "array.cells[0][0].rotation = 90\n", + "array.cells[0][2].rotation = 90\n", + "array.cells[2][0].rotation = 90\n", + "array.cells[2][2].rotation = 90" + ] + }, + { + "cell_type": "markdown", + "id": "e16ad1d8", + "metadata": {}, + "source": [ + "## Set up simulation and analyze\n", + "\n", + "Set up a simulation and analyze it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4360272e", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "setup = hfss.create_setup()\n", + "setup.props[\"Frequency\"] = \"5GHz\"\n", + "setup.props[\"MaximumPasses\"] = 3\n", + "hfss.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "5a1b9c15", + "metadata": {}, + "source": [ + "## Get far field data\n", + "\n", + "Get far field data. After the simulation completes, the far\n", + "field data is generated port by port and stored in a data class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60b205cb", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata = hfss.get_antenna_data(setup=hfss.nominal_adaptive, sphere=\"Infinite Sphere1\")" + ] + }, + { + "cell_type": "markdown", + "id": "1b1a30bb", + "metadata": {}, + "source": [ + "## Generate contour plot\n", + "\n", + "Generate a contour plot. You can define the Theta scan and Phi scan." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e2ac674f", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.farfield_data.plot_contour(\n", + " quantity=\"RealizedGain\",\n", + " title=\"Contour at {}Hz\".format(ffdata.farfield_data.frequency),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4f7b3f08", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT.\n", + "You can perform far field postprocessing without AEDT because the data is stored." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc5123f9", + "metadata": {}, + "outputs": [], + "source": [ + "metadata_file = ffdata.metadata_file\n", + "working_directory = hfss.working_directory" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b793f640", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "f1f70a67", + "metadata": {}, + "source": [ + "## Load far field data\n", + "\n", + "Load the stored far field data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f87df6d2", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata = FfdSolutionData(input_file=metadata_file)" + ] + }, + { + "cell_type": "markdown", + "id": "788e3a60", + "metadata": {}, + "source": [ + "## Generate contour plot\n", + "\n", + "Generate a contour plot. You can define the Theta scan\n", + "and Phi scan." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ed2700d", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.plot_contour(\n", + " quantity=\"RealizedGain\", title=\"Contour at {}Hz\".format(ffdata.frequency)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "122d75ef", + "metadata": {}, + "source": [ + "## Generate 2D cutout plots\n", + "\n", + "Generate 2D cutout plots. You can define the Theta scan\n", + "and Phi scan." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93803f11", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.plot_cut(\n", + " quantity=\"RealizedGain\",\n", + " primary_sweep=\"theta\",\n", + " secondary_sweep_value=[-180, -75, 75],\n", + " title=\"Azimuth at {}Hz\".format(ffdata.frequency),\n", + " quantity_format=\"dB10\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "522b7e60", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.plot_cut(\n", + " quantity=\"RealizedGain\",\n", + " primary_sweep=\"phi\",\n", + " secondary_sweep_value=30,\n", + " title=\"Elevation\",\n", + " quantity_format=\"dB10\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ec9d1f49", + "metadata": {}, + "source": [ + "## Generate 3D plot\n", + "\n", + "Generate 3D plots. You can define the Theta scan and Phi scan." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "398a047b", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.plot_3d(\n", + " quantity=\"RealizedGain\",\n", + " output_file=os.path.join(working_directory, \"Image.jpg\"),\n", + " show=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ca69d361", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d536a74a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/dipole.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/dipole.ipynb.txt new file mode 100644 index 00000000..bdd50b06 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/dipole.ipynb.txt @@ -0,0 +1,561 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6c7f7043", + "metadata": {}, + "source": [ + "# Dipole antenna\n", + "\n", + "This example shows how to use PyAEDT to create a dipole antenna in HFSS\n", + "and postprocess results.\n", + "\n", + "Keywords: **HFSS**, **modal**, **antenna**, **3D components**, **far field**." + ] + }, + { + "cell_type": "markdown", + "id": "3e228ba5", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac9c736e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cff2a15c", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "ef7f07c3", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8ec9d12", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "5e951487", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63ae0cda", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "cbe78847", + "metadata": {}, + "source": [ + "## Launch AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfbff884", + "metadata": {}, + "outputs": [], + "source": [ + "d = ansys.aedt.core.launch_desktop(\n", + " AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "46bc9667", + "metadata": {}, + "source": [ + "## Launch HFSS\n", + "\n", + "Create an HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fec90937", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"dipole.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " version=AEDT_VERSION, project=project_name, solution_type=\"Modal\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "938c1e54", + "metadata": {}, + "source": [ + "## Define variable\n", + "\n", + "Define a variable for the dipole length." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "286a6ca1", + "metadata": {}, + "outputs": [], + "source": [ + "hfss[\"l_dipole\"] = \"13.5cm\"" + ] + }, + { + "cell_type": "markdown", + "id": "06a1ffd5", + "metadata": {}, + "source": [ + "## Get 3D component from system library\n", + "\n", + "Get a 3D component from the ``syslib`` directory. For this example to run\n", + "correctly, you must get all geometry parameters of the 3D component or, in\n", + "case of an encrypted 3D component, create a dictionary of the parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51998f83", + "metadata": {}, + "outputs": [], + "source": [ + "compfile = hfss.components3d[\"Dipole_Antenna_DM\"]\n", + "geometryparams = hfss.get_components3d_vars(\"Dipole_Antenna_DM\")\n", + "geometryparams[\"dipole_length\"] = \"l_dipole\"\n", + "hfss.modeler.insert_3d_component(compfile, geometryparams)" + ] + }, + { + "cell_type": "markdown", + "id": "223312e2", + "metadata": {}, + "source": [ + "## Create boundaries\n", + "\n", + "Create an open region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42fc4f0b", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.create_open_region(frequency=\"1GHz\")" + ] + }, + { + "cell_type": "markdown", + "id": "301f8aa2", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup with a sweep to run the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f67506c", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(\"MySetup\")\n", + "setup.props[\"Frequency\"] = \"1GHz\"\n", + "setup.props[\"MaximumPasses\"] = 1\n", + "hfss.create_linear_count_sweep(\n", + " setup=setup.name,\n", + " units=\"GHz\",\n", + " start_frequency=0.5,\n", + " stop_frequency=1.5,\n", + " num_of_freq_points=101,\n", + " name=\"sweep1\",\n", + " sweep_type=\"Interpolating\",\n", + " interpolation_tol=3,\n", + " interpolation_max_solutions=255,\n", + " save_fields=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2bfacb7e", + "metadata": {}, + "source": [ + "## Run simulation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16310a4c", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.analyze_setup(name=\"MySetup\", cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "c4ee43a9", + "metadata": {}, + "source": [ + "### Postprocess\n", + "\n", + "Plot s-parameters and far field." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9358b9de", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.create_scattering(\"MyScattering\")\n", + "variations = hfss.available_variations.nominal_w_values_dict\n", + "variations[\"Freq\"] = [\"1GHz\"]\n", + "variations[\"Theta\"] = [\"All\"]\n", + "variations[\"Phi\"] = [\"All\"]\n", + "hfss.post.create_report(\n", + " \"db(GainTotal)\",\n", + " hfss.nominal_adaptive,\n", + " variations,\n", + " primary_sweep_variable=\"Theta\",\n", + " context=\"3D\",\n", + " report_category=\"Far Fields\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d00cd229", + "metadata": {}, + "source": [ + "Create a far fields report using the ``report_by_category.far field()`` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3607f954", + "metadata": {}, + "outputs": [], + "source": [ + "new_report = hfss.post.reports_by_category.far_field(\n", + " \"db(RealizedGainTotal)\", hfss.nominal_adaptive, \"3D\"\n", + ")\n", + "new_report.variations = variations\n", + "new_report.primary_sweep = \"Theta\"\n", + "new_report.create(\"Realized2D\")" + ] + }, + { + "cell_type": "markdown", + "id": "7919e37b", + "metadata": {}, + "source": [ + "Generate multiple plots using the ``new_report`` object. This code generates\n", + "2D and 3D polar plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dde1151f", + "metadata": {}, + "outputs": [], + "source": [ + "new_report.report_type = \"3D Polar Plot\"\n", + "new_report.secondary_sweep = \"Phi\"\n", + "new_report.create(\"Realized3D\")" + ] + }, + { + "cell_type": "markdown", + "id": "8c8c9f16", + "metadata": {}, + "source": [ + "Get solution data using the ``new_report`` object and postprocess or plot the\n", + "data outside AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "546ec604", + "metadata": {}, + "outputs": [], + "source": [ + "solution_data = new_report.get_solution_data()\n", + "solution_data.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "57eb939e", + "metadata": {}, + "source": [ + "Generate a far field plot by creating a postprocessing variable and assigning\n", + "it to a new coordinate system. You can use the ``post`` prefix to create a\n", + "postprocessing variable directly from a setter, or you can use the ``set_variable()``\n", + "method with an arbitrary name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1858e7e", + "metadata": {}, + "outputs": [], + "source": [ + "hfss[\"post_x\"] = 2\n", + "hfss.variable_manager.set_variable(name=\"y_post\", expression=1, is_post_processing=True)\n", + "hfss.modeler.create_coordinate_system(origin=[\"post_x\", \"y_post\", 0], name=\"CS_Post\")\n", + "hfss.insert_infinite_sphere(custom_coordinate_system=\"CS_Post\", name=\"Sphere_Custom\")" + ] + }, + { + "cell_type": "markdown", + "id": "8d8ef996", + "metadata": {}, + "source": [ + "## Retrieve solution data\n", + "\n", + "You can also process solution data using Python libraries like Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a79c14e", + "metadata": {}, + "outputs": [], + "source": [ + "new_report = hfss.post.reports_by_category.far_field(\n", + " \"GainTotal\", hfss.nominal_adaptive, \"3D\"\n", + ")\n", + "new_report.primary_sweep = \"Theta\"\n", + "new_report.far_field_sphere = \"3D\"\n", + "solutions = new_report.get_solution_data()" + ] + }, + { + "cell_type": "markdown", + "id": "481f82d8", + "metadata": {}, + "source": [ + "Generate a 3D plot using Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71194aea", + "metadata": {}, + "outputs": [], + "source": [ + "solutions.plot_3d()" + ] + }, + { + "cell_type": "markdown", + "id": "9b442614", + "metadata": {}, + "source": [ + "Generate a far fields plot using Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60bd4618", + "metadata": {}, + "outputs": [], + "source": [ + "new_report.far_field_sphere = \"Sphere_Custom\"\n", + "solutions_custom = new_report.get_solution_data()\n", + "solutions_custom.plot_3d()" + ] + }, + { + "cell_type": "markdown", + "id": "3b890196", + "metadata": {}, + "source": [ + "Generate a 2D plot using Matplotlib where you specify whether it is a polar\n", + "plot or a rectangular plot." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d1de51b", + "metadata": {}, + "outputs": [], + "source": [ + "solutions.plot(formula=\"db20\", is_polar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "bf88f591", + "metadata": {}, + "source": [ + "## Retrieve far-field data\n", + "\n", + "After the simulation completes, the far\n", + "field data is generated port by port and stored in a data class. You can use this data\n", + "once AEDT is released." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a25a217", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata = hfss.get_antenna_data(\n", + " sphere=\"Sphere_Custom\",\n", + " setup=hfss.nominal_adaptive,\n", + " frequencies=[\"1000MHz\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "37eda646", + "metadata": {}, + "source": [ + "## Generate 2D cutout plot\n", + "\n", + "Generate a 2D cutout plot. You can define the Theta scan\n", + "and Phi scan." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f57fb213", + "metadata": {}, + "outputs": [], + "source": [ + "ffdata.farfield_data.plot_cut(\n", + " primary_sweep=\"theta\",\n", + " secondary_sweep_value=0,\n", + " quantity=\"RealizedGain\",\n", + " title=\"FarField\",\n", + " quantity_format=\"dB20\",\n", + " is_polar=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7c59a32f", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6138bcc", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "18d6b358", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files.\n", + "The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8aeb280c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/fss_unitcell.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/fss_unitcell.ipynb.txt new file mode 100644 index 00000000..a90f497b --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/fss_unitcell.ipynb.txt @@ -0,0 +1,414 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "92f17c75", + "metadata": {}, + "source": [ + "# FSS unit cell simulation\n", + "\n", + "This example shows how to use PyAEDT to model and simulate a unit cell\n", + "for a frequency-selective surface in HFSS.\n", + "\n", + "Keywords: **HFSS**, **FSS**, **Floquet**." + ] + }, + { + "cell_type": "markdown", + "id": "841cf8c4", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c825a89d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58ef7788", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "c6cfa5ca", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db0cbf4a", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "0166630c", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a34e515", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "e3d4ac21", + "metadata": {}, + "source": [ + "## Launch AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4deb216e", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"FSS.aedt\")\n", + "d = ansys.aedt.core.launch_desktop(\n", + " AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "396395dd", + "metadata": {}, + "source": [ + "## Launch HFSS\n", + "\n", + "Create an HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed7a6ae7", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = ansys.aedt.core.Hfss(\n", + " version=AEDT_VERSION, project=project_name, solution_type=\"Modal\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "db41757e", + "metadata": {}, + "source": [ + "## Define variable\n", + "\n", + "Define a variable for the 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09650c1d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss[\"patch_dim\"] = \"10mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "0dbb4115", + "metadata": {}, + "source": [ + "## Set up model\n", + "\n", + "Download the 3D component from the example data and insert the 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c0c9a68", + "metadata": {}, + "outputs": [], + "source": [ + "unitcell_3d_component_path = ansys.aedt.core.downloads.download_FSS_3dcomponent(\n", + " destination=temp_folder.name\n", + ")\n", + "unitcell_path = os.path.join(unitcell_3d_component_path, \"FSS_unitcell_23R2.a3dcomp\")\n", + "comp = hfss.modeler.insert_3d_component(unitcell_path)" + ] + }, + { + "cell_type": "markdown", + "id": "77ff61d1", + "metadata": {}, + "source": [ + "Assign the parameter to the 3D component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "932550a2", + "metadata": {}, + "outputs": [], + "source": [ + "component_name = hfss.modeler.user_defined_component_names\n", + "comp.parameters[\"a\"] = \"patch_dim\"" + ] + }, + { + "cell_type": "markdown", + "id": "37b6cc57", + "metadata": {}, + "source": [ + "Create an open region along +Z direction for unit cell analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c7e1e19", + "metadata": {}, + "outputs": [], + "source": [ + "bounding_dimensions = hfss.modeler.get_bounding_dimension()\n", + "\n", + "periodicity_x = bounding_dimensions[0]\n", + "periodicity_y = bounding_dimensions[1]\n", + "\n", + "region = hfss.modeler.create_air_region(\n", + " z_pos=10 * bounding_dimensions[2],\n", + " is_percentage=False,\n", + ")\n", + "\n", + "[x_min, y_min, z_min, x_max, y_max, z_max] = region.bounding_box" + ] + }, + { + "cell_type": "markdown", + "id": "d02bc8fb", + "metadata": {}, + "source": [ + "Assign the lattice pair boundary condition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67411048", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.auto_assign_lattice_pairs(assignment=region.name)" + ] + }, + { + "cell_type": "markdown", + "id": "0e5ce9b9", + "metadata": {}, + "source": [ + "Define the Floquet port." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57a3102f", + "metadata": {}, + "outputs": [], + "source": [ + "id_z_pos = region.top_face_z\n", + "hfss.create_floquet_port(\n", + " assignment=id_z_pos,\n", + " lattice_origin=[0, 0, z_max],\n", + " lattice_a_end=[0, y_max, z_max],\n", + " lattice_b_end=[x_max, 0, z_max],\n", + " name=\"port_z_max\",\n", + " deembed_distance=10 * bounding_dimensions[2],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "48851ac2", + "metadata": {}, + "source": [ + "Create a solution setup, including the frequency sweep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56f8cdfa", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(\"MySetup\")\n", + "setup.props[\"Frequency\"] = \"10GHz\"\n", + "setup.props[\"MaximumPasses\"] = 10\n", + "hfss.create_linear_count_sweep(\n", + " setup=setup.name,\n", + " units=\"GHz\",\n", + " start_frequency=6,\n", + " stop_frequency=15,\n", + " num_of_freq_points=51,\n", + " name=\"sweep1\",\n", + " sweep_type=\"Interpolating\",\n", + " interpolation_tol=6,\n", + " save_fields=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ad30c609", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Create S-parameter reports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "971b8a90", + "metadata": {}, + "outputs": [], + "source": [ + "all_quantities = hfss.post.available_report_quantities()\n", + "str_mag = []\n", + "str_ang = []\n", + "\n", + "variation = {\"Freq\": [\"All\"]}\n", + "\n", + "for i in all_quantities:\n", + " str_mag.append(\"mag(\" + i + \")\")\n", + " str_ang.append(\"ang_deg(\" + i + \")\")\n", + "\n", + "hfss.post.create_report(\n", + " expressions=str_mag,\n", + " variations=variation,\n", + " plot_name=\"magnitude_plot\",\n", + ")\n", + "hfss.post.create_report(\n", + " expressions=str_ang,\n", + " variations=variation,\n", + " plot_name=\"phase_plot\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "16caea58", + "metadata": {}, + "source": [ + "## Save and run simulation\n", + "\n", + "Save and run the simulation. Uncomment the following line to run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54ee85a3", + "metadata": {}, + "outputs": [], + "source": [ + "# hfss.analyze()\n", + "hfss.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "71c1239a", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2550e07", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "07f623d8", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8429316", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/index.rst.txt b/version/dev/_sources/examples/high_frequency/antenna/index.rst.txt new file mode 100644 index 00000000..532af2f8 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/index.rst.txt @@ -0,0 +1,107 @@ +Antenna +~~~~~~~ +These examples use PyAEDT to show some antenna applications. + +.. grid:: 2 + + .. grid-item-card:: Dipole antenna + :padding: 2 2 2 2 + :link: dipole + :link-type: doc + + .. image:: _static/dipole.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a dipole antenna in HFSS and postprocess results. + + .. grid-item-card:: Component antenna array + :padding: 2 2 2 2 + :link: array + :link-type: doc + + .. image:: _static/array.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an antenna array. + + .. grid-item-card:: Probe-fed patch antenna + :padding: 2 2 2 2 + :link: patch + :link-type: doc + + .. image:: _static/patch.png + :alt: Patch + :width: 250px + :height: 200px + :align: center + + This example shows how to use the Stackup3D class to create and analyze a patch antenna in HFSS. + + .. grid-item-card:: FSS unit cell simulation + :padding: 2 2 2 2 + :link: fss_unitcell + :link-type: doc + + .. image:: _static/unitcell.png + :alt: FSS + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to model and simulate a unit cell for a frequency-selective surface in HFSS. + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: ../../aedt_general/modeler/circuit_schematic + :link-type: doc + + .. image:: ../../aedt_general/modeler/_static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Large scenarios + :padding: 2 2 2 2 + :link: large_scenarios/index + :link-type: doc + + .. image:: _static/car_w_pedestrians.png + :alt: FSS + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some general capabilities of HFSS SBR+ for large scenarios. + + .. grid-item-card:: RF interference + :padding: 2 2 2 2 + :link: interferences/index + :link-type: doc + + .. image:: _static/emit_simple_cosite.png + :alt: EMIT logo + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some general capabilities of EMIT for RF interference. + + .. toctree:: + :hidden: + + dipole + array + patch + fss_unitcell + ../../aedt_general/modeler/circuit_schematic + large_scenarios/index + interferences/index diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/antenna.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/antenna.ipynb.txt new file mode 100644 index 00000000..ebdcb071 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/antenna.ipynb.txt @@ -0,0 +1,277 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "09618d31", + "metadata": {}, + "source": [ + "# Antenna\n", + "\n", + "This example shows how to create a project in EMIT for\n", + "the simulation of an antenna using HFSS.\n", + "\n", + "\n", + "\n", + "Keywords: **EMIT**, **Antenna**." + ] + }, + { + "cell_type": "markdown", + "id": "4db6727b", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a0da2fc", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4def4ccc", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "27fcc963", + "metadata": {}, + "source": [ + "from ansys.aedt.core.emit_core.emit_constants import ResultType, TxRxMode" + ] + }, + { + "cell_type": "markdown", + "id": "e6e447be", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "950c5a3e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "c3bc9a47", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50e68082", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "4ce15262", + "metadata": {}, + "source": [ + "## Launch AEDT with EMIT\n", + "\n", + "Launch AEDT with EMIT. The ``launch_desktop()`` method initializes AEDT\n", + "using the specified version. The second argument can be set to ``True`` to\n", + "run AEDT in non-graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22701f2f", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = ansys.aedt.core.generate_unique_project_name(\n", + " root_name=temp_folder.name, project_name=\"antenna_cosite\"\n", + ")\n", + "d = ansys.aedt.core.launch_desktop(AEDT_VERSION, NG_MODE, new_desktop=True)\n", + "aedtapp = ansys.aedt.core.Emit(project_name, version=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "69bf3fb7", + "metadata": {}, + "source": [ + "## Create and connect EMIT components\n", + "\n", + "Create three radios and connect an antenna to each one." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17921f5a", + "metadata": {}, + "outputs": [], + "source": [ + "rad1 = aedtapp.modeler.components.create_component(\"New Radio\")\n", + "ant1 = aedtapp.modeler.components.create_component(\"Antenna\")\n", + "if rad1 and ant1:\n", + " ant1.move_and_connect_to(rad1)" + ] + }, + { + "cell_type": "markdown", + "id": "dc3430f3", + "metadata": {}, + "source": [ + "## Place radio/antenna pair\n", + "\n", + "Use the ``create_radio_antenna()`` method to place the radio/antenna pair. The first\n", + "argument is the type of radio. The second argument is the name to\n", + "assign to the radio." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0eba2a23", + "metadata": {}, + "outputs": [], + "source": [ + "rad2, ant2 = aedtapp.modeler.components.create_radio_antenna(\"GPS Receiver\")\n", + "rad3, ant3 = aedtapp.modeler.components.create_radio_antenna(\n", + " \"Bluetooth Low Energy (LE)\", \"Bluetooth\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b15b6501", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Define the RF environment\n", + "\n", + "Specify the RF coupling among antennas.\n", + "This functionality is not yet implemented in the API, but it can be entered from the UI.\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "a8191aca", + "metadata": {}, + "source": [ + "## Run EMIT simulation\n", + "\n", + "Run the EMIT simulation.\n", + "\n", + "This part of the example requires Ansys AEDT 2023 R2." + ] + }, + { + "cell_type": "markdown", + "id": "281d6a78", + "metadata": {}, + "source": [ + "> **Note:** You can uncomment the following code.\n", + "\n", + "if AEDT_VERSION > \"2023.1\":\n", + " rev = aedtapp.results.analyze()\n", + " rx_bands = rev.get_band_names(rad2.name, TxRxMode.RX)\n", + " tx_bands = rev.get_band_names(rad3.name, TxRxMode.TX)\n", + " domain = aedtapp.results.interaction_domain()\n", + " domain.set_receiver(rad2.name, rx_bands[0], -1)\n", + " domain.set_interferer(rad3.name, tx_bands[0])\n", + " interaction = rev.run(domain)\n", + " worst = interaction.get_worst_instance(ResultType.EMI)\n", + " if worst.has_valid_values():\n", + " emi = worst.get_value(ResultType.EMI)\n", + " print(\"Worst case interference is: {} dB\".format(emi))" + ] + }, + { + "cell_type": "markdown", + "id": "744735f3", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2ca7e39", + "metadata": {}, + "outputs": [], + "source": [ + "aedtapp.save_project()\n", + "aedtapp.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "8a8402ba", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0e35b92", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/hfss_emit.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/hfss_emit.ipynb.txt new file mode 100644 index 00000000..9b9c3a0f --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/hfss_emit.ipynb.txt @@ -0,0 +1,370 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0b660e43", + "metadata": {}, + "source": [ + "# HFSS to EMIT coupling\n", + "\n", + "This example shows how to link an HFSS design\n", + "to EMIT and model RF interference among various components.\n", + "\n", + "\n", + "\n", + "> **Note:** This example uses the ``Cell Phone RFI Desense``\n", + "> project that is available with the AEDT installation in the\n", + "> ``\\Examples\\EMIT\\`` directory.\n", + "\n", + "Keywords: **EMIT**, **Coupling**." + ] + }, + { + "cell_type": "markdown", + "id": "41df041c", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ea2a67e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import shutil\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0cd0598c", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.emit_core.emit_constants import ResultType, TxRxMode" + ] + }, + { + "cell_type": "markdown", + "id": "be60635e", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c713880c", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "480b820e", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f6304c4", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "d794f4e6", + "metadata": {}, + "source": [ + "## Launch AEDT with EMIT\n", + "\n", + "Launch AEDT with EMIT. The ``Desktop`` class initializes AEDT and starts it\n", + "on the specified version and in the specified graphical mode.\n", + "A temporary working directory is created using ``tempfile``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "879efb2f", + "metadata": {}, + "outputs": [], + "source": [ + "d = ansys.aedt.core.launch_desktop(\n", + " version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a00f803e", + "metadata": {}, + "source": [ + "## Copy example files\n", + "\n", + "Copy the ``Cell Phone RFT Defense`` example data from the\n", + "installed ``Examples`` directory to the temporary working\n", + "directory.\n", + "\n", + "> **Note:** The HFSS design from the installed example\n", + "> used to model the RF environment\n", + "> has been pre-solved. Hence, the results folder is copied and\n", + "> the RF interference between transceivers is calculated in EMIT using\n", + "> results from the linked HFSS design.\n", + "\n", + "The following lambda functions help create file and directory\n", + "names when copying data from the ``Examples`` directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba3552c7", + "metadata": {}, + "outputs": [], + "source": [ + "file_name = lambda s: s + \".aedt\"\n", + "results_name = lambda s: s + \".aedtresults\"\n", + "pdf_name = lambda s: s + \" Example.pdf\"" + ] + }, + { + "cell_type": "markdown", + "id": "ed13e863", + "metadata": {}, + "source": [ + "Build the names of the source files for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b94b99d9", + "metadata": {}, + "outputs": [], + "source": [ + "example = \"Cell Phone RFI Desense\"\n", + "example_dir = os.path.join(d.install_path, \"Examples\\\\EMIT\")\n", + "example_project = os.path.join(example_dir, file_name(example))\n", + "example_results_folder = os.path.join(example_dir, results_name(example))\n", + "example_pdf = os.path.join(example_dir, pdf_name(example))" + ] + }, + { + "cell_type": "markdown", + "id": "8a28354a", + "metadata": {}, + "source": [ + "Copy the files to the temporary working directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89be0678", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = shutil.copyfile(\n", + " example_project, os.path.join(temp_folder.name, file_name(example))\n", + ")\n", + "results_folder = shutil.copytree(\n", + " example_results_folder, os.path.join(temp_folder.name, results_name(example))\n", + ")\n", + "project_pdf = shutil.copyfile(\n", + " example_pdf, os.path.join(temp_folder.name, pdf_name(example))\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "073f2879", + "metadata": {}, + "source": [ + "Open the project in the working directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d83de36d", + "metadata": {}, + "outputs": [], + "source": [ + "aedtapp = ansys.aedt.core.Emit(project_name, version=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "8a861a5a", + "metadata": {}, + "source": [ + "## Create and connect EMIT components\n", + "\n", + "Create two radios with antennas connected to each one." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d89cc52", + "metadata": {}, + "outputs": [], + "source": [ + "rad1, ant1 = aedtapp.modeler.components.create_radio_antenna(\n", + " \"Bluetooth Low Energy (LE)\"\n", + ")\n", + "rad2, ant2 = aedtapp.modeler.components.create_radio_antenna(\n", + " \"Bluetooth Low Energy (LE)\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6b87a6bd", + "metadata": {}, + "source": [ + "## Define coupling among RF systems\n", + "\n", + "Define coupling among the RF systems." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c9e6788", + "metadata": {}, + "outputs": [], + "source": [ + "for link in aedtapp.couplings.linkable_design_names:\n", + " aedtapp.couplings.add_link(link)\n", + " print('linked \"' + link + '\".')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85ace7fd", + "metadata": {}, + "outputs": [], + "source": [ + "for link in aedtapp.couplings.coupling_names:\n", + " aedtapp.couplings.update_link(link)\n", + " print('linked \"' + link + '\".')" + ] + }, + { + "cell_type": "markdown", + "id": "0411db24", + "metadata": {}, + "source": [ + "## Calculate RF interference\n", + "\n", + "Run the EMIT simulation. This portion of the EMIT API is not yet implemented.\n", + "\n", + "This part of the example requires Ansys AEDT 2023 R2." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2e15a8e", + "metadata": {}, + "outputs": [], + "source": [ + "if AEDT_VERSION > \"2023.1\":\n", + " rev = aedtapp.results.analyze()\n", + " rx_bands = rev.get_band_names(rad1.name, TxRxMode.RX)\n", + " tx_bands = rev.get_band_names(rad2.name, TxRxMode.TX)\n", + " domain = aedtapp.results.interaction_domain()\n", + " domain.set_receiver(rad1.name, rx_bands[0], -1)\n", + " domain.set_interferer(rad2.name, tx_bands[0])\n", + " interaction = rev.run(domain)\n", + " worst = interaction.get_worst_instance(ResultType.EMI)\n", + " if worst.has_valid_values():\n", + " emi = worst.get_value(ResultType.EMI)\n", + " print(\"Worst case interference is: {} dB\".format(emi))" + ] + }, + { + "cell_type": "markdown", + "id": "5308318d", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "103faa04", + "metadata": {}, + "outputs": [], + "source": [ + "aedtapp.save_project()\n", + "aedtapp.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "39b1a52a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "549a0d0a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/index.rst.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/index.rst.txt new file mode 100644 index 00000000..b8f1e62f --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/index.rst.txt @@ -0,0 +1,81 @@ +RF interference +~~~~~~~~~~~~~~~ +These examples use PyAEDT to show some general capabilities of EMIT for RF interference + +.. grid:: 2 + + .. grid-item-card:: Antenna + :padding: 2 2 2 2 + :link: antenna + :link-type: doc + + .. image:: _static/emit.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project in EMIT for the simulation of an antenna using HFSS. + + .. grid-item-card:: HFSS to EMIT coupling + :padding: 2 2 2 2 + :link: hfss_emit + :link-type: doc + + .. image:: _static/emit_hfss.png + :alt: EMIT HFSS + :width: 250px + :height: 200px + :align: center + + This example shows how to link an HFSS design to EMIT and model RF interference among various components. + + .. grid-item-card:: Interference type classification + :padding: 2 2 2 2 + :link: interference + :link-type: doc + + .. image:: _static/interference.png + :alt: EMIT HFSS + :width: 250px + :height: 200px + :align: center + + This example shows how to load an existing AEDT EMIT design and analyze the results to classify the worst-case interference. + + .. grid-item-card:: Compute receiver protection levels + :padding: 2 2 2 2 + :link: interference_type + :link-type: doc + + .. image:: _static/protection.png + :alt: EMIT protection + :width: 250px + :height: 200px + :align: center + + This example shows how to open an AEDT project with an EMIT design and analyze the results to determine if + the received power at the input to each receiver exceeds the specified protection levels. + + .. grid-item-card:: Interference type classification using a GUI + :padding: 2 2 2 2 + :link: interference_type + :link-type: doc + + .. image:: _static/interference_type.png + :alt: EMIT protection + :width: 250px + :height: 200px + :align: center + + This example uses a GUI to open an AEDT project with an EMIT design and analyze the results to classify + the worst-case interference. + + .. toctree:: + :hidden: + + antenna + hfss_emit + interference + protection + interference_type diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/interference.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/interference.ipynb.txt new file mode 100644 index 00000000..adf75a88 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/interference.ipynb.txt @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "387517ad", + "metadata": {}, + "source": [ + "# Interference type classification\n", + "\n", + "This example shows how to load an existing AEDT EMIT\n", + "design and analyze the results to classify the\n", + "worst-case interference.\n", + "\n", + "Keywords: **EMIT**, **interference**." + ] + }, + { + "cell_type": "markdown", + "id": "98cb0c65", + "metadata": {}, + "source": [ + "## Perform imports and define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7dd11bf8", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import tempfile\n", + "\n", + "import ansys.aedt.core\n", + "import plotly.graph_objects as go\n", + "from ansys.aedt.core import Emit\n", + "from ansys.aedt.core.emit_core.emit_constants import InterfererType\n" + ] + }, + { + "cell_type": "markdown", + "id": "12144220", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84e3236d", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "a04ef8b6", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebce8b6c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "14e91e77", + "metadata": {}, + "source": [ + "Check that EMIT 2023.2 or later is installed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57673bf7", + "metadata": {}, + "outputs": [], + "source": [ + "if AEDT_VERSION <= \"2023.1\":\n", + " print(\"Warning: This example requires AEDT 2023.2 or later.\")\n", + " sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "ba75bdcc", + "metadata": {}, + "source": [ + "Download project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "613d1925", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = ansys.aedt.core.downloads.download_file(\n", + " \"emit\", \"interference.aedtz\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ba6cc70d", + "metadata": {}, + "source": [ + "## Launch EMIT and open project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f11e2ad", + "metadata": {}, + "outputs": [], + "source": [ + "emitapp = Emit(\n", + " non_graphical=NG_MODE, new_desktop=True, project=project_name, version=AEDT_VERSION\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "21ff5e30", + "metadata": {}, + "source": [ + "## Get lists of transmitters and receivers\n", + "\n", + "Get lists of all transmitters and receivers in the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12e64919", + "metadata": {}, + "outputs": [], + "source": [ + "rev = emitapp.results.analyze()\n", + "tx_interferer = InterfererType().TRANSMITTERS\n", + "rx_radios = rev.get_receiver_names()\n", + "tx_radios = rev.get_interferer_names(tx_interferer)\n", + "domain = emitapp.results.interaction_domain()\n", + "\n", + "if tx_radios is None or rx_radios is None:\n", + " print(\"No receivers or transmitters are in the design.\")\n", + " sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "f4a62dc6", + "metadata": {}, + "source": [ + "## Classify the interference\n", + "\n", + "Iterate over all the transmitters and receivers and compute the power\n", + "at the input to each receiver due to each of the transmitters. Compute\n", + "which type of interference occurred, if any." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b99c31e", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "power_matrix = []\n", + "all_colors = []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fec8d440", + "metadata": {}, + "outputs": [], + "source": [ + "all_colors, power_matrix = rev.interference_type_classification(\n", + " domain, use_filter=False, filter_list=[]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7f61067f", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65b3d0c1", + "metadata": {}, + "outputs": [], + "source": [ + "emitapp.release_desktop()" + ] + }, + { + "cell_type": "markdown", + "id": "c5b9f2d4", + "metadata": {}, + "source": [ + "## Create a scenario matrix view\n", + "\n", + "Create a scenario matrix view with the transmitters defined across the top\n", + "and receivers down the left-most column. The power at the input to each\n", + "receiver is shown in each cell of the matrix and color-coded based on the\n", + "interference type.\n", + "\n", + "Set up colors to visualize results in a table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f497f6fa", + "metadata": { + "lines_to_end_of_cell_marker": 2, + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "table_colors = {\n", + " \"green\": \"#7d73ca\",\n", + " \"yellow\": \"#d359a2\",\n", + " \"orange\": \"#ff6361\",\n", + " \"red\": \"#ffa600\",\n", + " \"white\": \"#ffffff\",\n", + "}\n", + "header_color = \"grey\"\n", + "\n", + "\n", + "def create_scenario_view(emis, colors, tx_radios, rx_radios):\n", + " \"\"\"Create a scenario matrix-like table with the higher received\n", + " power for each Tx-Rx radio combination. The colors\n", + " used for the scenario matrix view are based on the interference type.\"\"\"\n", + "\n", + " all_colors = []\n", + " for color in colors:\n", + " col = []\n", + " for cell in color:\n", + " col.append(table_colors[cell])\n", + " all_colors.append(col)\n", + "\n", + " fig = go.Figure(\n", + " data=[\n", + " go.Table(\n", + " header=dict(\n", + " values=[\n", + " \"Tx/Rx\",\n", + " \"{}\".format(tx_radios[0]),\n", + " \"{}\".format(tx_radios[1]),\n", + " ],\n", + " line_color=\"darkslategray\",\n", + " fill_color=\"grey\",\n", + " align=[\"left\", \"center\"],\n", + " font=dict(color=\"white\", size=16),\n", + " ),\n", + " cells=dict(\n", + " values=[rx_radios, emis[0], emis[1]],\n", + " line_color=\"darkslategray\",\n", + " fill_color=[\"white\", all_colors[0], all_colors[1]],\n", + " align=[\"left\", \"center\"],\n", + " height=25,\n", + " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", + " ),\n", + " )\n", + " ]\n", + " )\n", + " fig.update_layout(\n", + " title=dict(\n", + " text=\"Interference Type Classification\",\n", + " font=dict(color=\"darkslategray\", size=20),\n", + " x=0.5,\n", + " ),\n", + " width=600,\n", + " )\n", + " fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "70889994", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Create a legend\n", + "\n", + "Create a legend, defining the interference types and colors used to display the results of\n", + "the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39c257af", + "metadata": {}, + "outputs": [], + "source": [ + "def create_legend_table():\n", + " \"\"\"Create a table showing the interference types.\"\"\"\n", + " classifications = [\n", + " \"In-band/In-band\",\n", + " \"Out-of-band/In-band\",\n", + " \"In-band/Out-of-band\",\n", + " \"Out-of-band/Out-of-band\",\n", + " ]\n", + " fig = go.Figure(\n", + " data=[\n", + " go.Table(\n", + " header=dict(\n", + " values=[\"Interference Type (Source/Victim)\"],\n", + " line_color=\"darkslategray\",\n", + " fill_color=header_color,\n", + " align=[\"center\"],\n", + " font=dict(color=\"white\", size=16),\n", + " ),\n", + " cells=dict(\n", + " values=[classifications],\n", + " line_color=\"darkslategray\",\n", + " fill_color=[\n", + " [\n", + " table_colors[\"red\"],\n", + " table_colors[\"orange\"],\n", + " table_colors[\"yellow\"],\n", + " table_colors[\"green\"],\n", + " ]\n", + " ],\n", + " align=[\"center\"],\n", + " height=25,\n", + " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", + " ),\n", + " )\n", + " ]\n", + " )\n", + " fig.update_layout(\n", + " title=dict(\n", + " text=\"Interference Type Classification\",\n", + " font=dict(color=\"darkslategray\", size=20),\n", + " x=0.5,\n", + " ),\n", + " width=600,\n", + " )\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ecad4e0", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a scenario view for all the interference types\n", + "create_scenario_view(power_matrix, all_colors, tx_radios, rx_radios)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64d17e07", + "metadata": {}, + "outputs": [], + "source": [ + "# Create a legend for the interference types\n", + "create_legend_table()" + ] + }, + { + "cell_type": "markdown", + "id": "0e4dc03e", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70cffad7", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/interference_type.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/interference_type.ipynb.txt new file mode 100644 index 00000000..ed66811b --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/interference_type.ipynb.txt @@ -0,0 +1,880 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "62d57836", + "metadata": {}, + "source": [ + "# Interference type classification using a GUI\n", + "\n", + "This example uses a GUI to open an AEDT project with\n", + "an EMIT design and analyze the results to classify the\n", + "worst-case interference.\n", + "\n", + "> **Note:** This example requires PySide6.\n", + "\n", + "Keywords: **EMIT**, **user interface**." + ] + }, + { + "cell_type": "markdown", + "id": "3af75636", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f61bc5d8", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e499d402", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import openpyxl\n", + "from ansys.aedt.core import get_pyaedt_app\n", + "from ansys.aedt.core.emit_core.emit_constants import InterfererType\n", + "from openpyxl.styles import PatternFill\n", + "from PySide6 import QtCore, QtGui, QtUiTools, QtWidgets" + ] + }, + { + "cell_type": "markdown", + "id": "0bbbdd7b", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac5ce46f", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "3652e655", + "metadata": {}, + "source": [ + "Uncomment the following code if there are Qt plugin errors\n", + "import PySide6\n", + "dirname = os.path.dirname(PySide6.__file__)\n", + "plugin_path = os.path.join(dirname, 'plugins', 'platforms')\n", + "os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path" + ] + }, + { + "cell_type": "markdown", + "id": "904803d3", + "metadata": {}, + "source": [ + "## Launch EMIT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fce9ace1", + "metadata": {}, + "outputs": [], + "source": [ + "desktop = ansys.aedt.core.launch_desktop(AEDT_VERSION, NG_MODE, new_desktop=True)" + ] + }, + { + "cell_type": "markdown", + "id": "80ed5771", + "metadata": {}, + "source": [ + "## Add ``EmitApiPython`` module to system path to import it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2322538", + "metadata": {}, + "outputs": [], + "source": [ + "emit_path = os.path.join(desktop.install_path, \"Delcross\")\n", + "sys.path.insert(0, emit_path)\n", + "import EmitApiPython" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97a7ad19", + "metadata": {}, + "outputs": [], + "source": [ + "api = EmitApiPython.EmitApi()" + ] + }, + { + "cell_type": "markdown", + "id": "b933cfac", + "metadata": {}, + "source": [ + "## Define GUI\n", + "\n", + "Define the UI extension file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0aa1646", + "metadata": { + "lines_to_next_cell": 1 + }, + "outputs": [], + "source": [ + "ui_file = ansys.aedt.core.downloads.download_file(\"emit\", \"interference_gui.ui\")\n", + "Ui_MainWindow, _ = QtUiTools.loadUiType(ui_file)" + ] + }, + { + "cell_type": "markdown", + "id": "c23bcfa0", + "metadata": {}, + "source": [ + "Customize the GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e90fdc4", + "metadata": {}, + "outputs": [], + "source": [ + "class DoubleDelegate(QtWidgets.QStyledItemDelegate):\n", + " def __init__(self, decimals, values, max_power, min_power):\n", + " super().__init__()\n", + " self.decimals = decimals\n", + " self.values = values\n", + " self.max_power = max_power\n", + " self.min_power = min_power\n", + "\n", + " def createEditor(self, parent, option, index):\n", + " editor = super().createEditor(parent, option, index)\n", + " if isinstance(editor, QtWidgets.QLineEdit):\n", + " validator = QtGui.QDoubleValidator(parent)\n", + " num_rows = len(self.values)\n", + " cur_row = index.row()\n", + " if cur_row == 0:\n", + " min_val = self.values[1]\n", + " max_val = self.max_power\n", + " elif cur_row == num_rows - 1:\n", + " min_val = self.min_power\n", + " max_val = self.values[cur_row - 1]\n", + " else:\n", + " min_val = self.values[cur_row + 1]\n", + " max_val = self.values[cur_row - 1]\n", + " validator.setRange(min_val, max_val, self.decimals)\n", + " validator.setNotation(QtGui.QDoubleValidator.Notation.StandardNotation)\n", + " editor.setValidator(validator)\n", + " return editor\n", + "\n", + " def update_values(self, values):\n", + " self.values = values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40a0c5fa", + "metadata": {}, + "outputs": [], + "source": [ + "class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):\n", + " def __init__(self):\n", + " super(MainWindow, self).__init__()\n", + " self.emitapp = None\n", + " self.populating_dropdown = False\n", + " self.setupUi(self)\n", + " self.setup_widgets()\n", + "\n", + " # ## Setup widgets\n", + " #\n", + " # Define all widgets from the UI file, connect the widgets to functions, define\n", + " # table colors, and format table settings.\n", + "\n", + " def setup_widgets(self):\n", + " # Widget definitions for file selection/tab management\n", + " self.file_select_btn = self.findChild(QtWidgets.QToolButton, \"file_select_btn\")\n", + " self.file_path_box = self.findChild(QtWidgets.QLineEdit, \"file_path_box\")\n", + " self.design_name_dropdown = self.findChild(\n", + " QtWidgets.QComboBox, \"design_name_dropdown\"\n", + " )\n", + " self.design_name_dropdown.setEnabled(True)\n", + " self.tab_widget = self.findChild(QtWidgets.QTabWidget, \"tab_widget\")\n", + "\n", + " # Widget definitions for protection level classification\n", + " self.protection_results_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"protection_results_btn\"\n", + " )\n", + " self.protection_matrix = self.findChild(\n", + " QtWidgets.QTableWidget, \"protection_matrix\"\n", + " )\n", + " self.protection_legend_table = self.findChild(\n", + " QtWidgets.QTableWidget, \"protection_legend_table\"\n", + " )\n", + "\n", + " self.damage_check = self.findChild(QtWidgets.QCheckBox, \"damage_check\")\n", + " self.overload_check = self.findChild(QtWidgets.QCheckBox, \"overload_check\")\n", + " self.intermodulation_check = self.findChild(\n", + " QtWidgets.QCheckBox, \"intermodulation_check\"\n", + " )\n", + " self.desensitization_check = self.findChild(\n", + " QtWidgets.QCheckBox, \"desensitization_check\"\n", + " )\n", + " self.protection_export_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"protection_export_btn\"\n", + " )\n", + " self.radio_specific_levels = self.findChild(\n", + " QtWidgets.QCheckBox, \"radio_specific_levels\"\n", + " )\n", + " self.radio_dropdown = self.findChild(QtWidgets.QComboBox, \"radio_dropdown\")\n", + " self.protection_save_img_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"protection_save_img_btn\"\n", + " )\n", + "\n", + " # warning label\n", + " self.warning_label = self.findChild(QtWidgets.QLabel, \"warnings\")\n", + " myFont = QtGui.QFont()\n", + " myFont.setBold(True)\n", + " self.warning_label.setFont(myFont)\n", + " self.warning_label.setHidden(True)\n", + " self.design_name_dropdown.currentIndexChanged.connect(\n", + " self.design_dropdown_changed\n", + " )\n", + "\n", + " # Setup for protection level buttons and table\n", + " self.protection_results_btn.setEnabled(False)\n", + " self.protection_export_btn.setEnabled(False)\n", + " self.protection_save_img_btn.setEnabled(False)\n", + " self.file_select_btn.clicked.connect(self.open_file_dialog)\n", + " self.protection_export_btn.clicked.connect(self.save_results_excel)\n", + " self.protection_results_btn.clicked.connect(self.protection_results)\n", + " self.protection_legend_table.resizeRowsToContents()\n", + " self.protection_legend_table.resizeColumnsToContents()\n", + " self.damage_check.stateChanged.connect(self.protection_results)\n", + " self.overload_check.stateChanged.connect(self.protection_results)\n", + " self.intermodulation_check.stateChanged.connect(self.protection_results)\n", + " self.desensitization_check.stateChanged.connect(self.protection_results)\n", + " self.protection_legend_table.setEditTriggers(\n", + " QtWidgets.QTableWidget.DoubleClicked\n", + " )\n", + " self.global_protection_level = True\n", + " self.protection_levels = {}\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " self.protection_levels[\"Global\"] = values\n", + " self.changing = False\n", + " self.radio_dropdown.currentIndexChanged.connect(self.radio_dropdown_changed)\n", + " self.protection_legend_table.itemChanged.connect(self.table_changed)\n", + " self.protection_save_img_btn.clicked.connect(self.save_image)\n", + "\n", + " # Widget definitions for interference type\n", + " self.interference_results_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"interference_results_btn\"\n", + " )\n", + " self.interference_matrix = self.findChild(\n", + " QtWidgets.QTableWidget, \"interference_matrix\"\n", + " )\n", + " self.interference_legend_table = self.findChild(\n", + " QtWidgets.QTableWidget, \"interference_legend_table\"\n", + " )\n", + "\n", + " # set the items read only\n", + " for i in range(0, self.interference_legend_table.rowCount()):\n", + " item = self.interference_legend_table.item(i, 0)\n", + " item.setFlags(QtCore.Qt.ItemIsEnabled)\n", + " self.interference_legend_table.setItem(i, 0, item)\n", + "\n", + " self.in_in_check = self.findChild(QtWidgets.QCheckBox, \"in_in_check\")\n", + " self.in_out_check = self.findChild(QtWidgets.QCheckBox, \"in_out_check\")\n", + " self.out_in_check = self.findChild(QtWidgets.QCheckBox, \"out_in_check\")\n", + " self.out_out_check = self.findChild(QtWidgets.QCheckBox, \"out_out_check\")\n", + " self.interference_export_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"interference_export_btn\"\n", + " )\n", + " self.interference_save_img_btn = self.findChild(\n", + " QtWidgets.QPushButton, \"interference_save_img_btn\"\n", + " )\n", + "\n", + " # Setup for interference type buttons and table\n", + " self.interference_results_btn.setEnabled(False)\n", + " self.interference_export_btn.setEnabled(False)\n", + " self.interference_save_img_btn.setEnabled(False)\n", + " self.interference_export_btn.clicked.connect(self.save_results_excel)\n", + " self.interference_results_btn.clicked.connect(self.interference_results)\n", + " self.interference_legend_table.resizeRowsToContents()\n", + " self.interference_legend_table.resizeColumnsToContents()\n", + " self.in_in_check.stateChanged.connect(self.interference_results)\n", + " self.in_out_check.stateChanged.connect(self.interference_results)\n", + " self.out_in_check.stateChanged.connect(self.interference_results)\n", + " self.out_out_check.stateChanged.connect(self.interference_results)\n", + " self.radio_specific_levels.stateChanged.connect(self.radio_specific)\n", + " self.interference_save_img_btn.clicked.connect(self.save_image)\n", + "\n", + " # Color definition dictionary and previous project/design names\n", + " self.color_dict = {\n", + " \"green\": [QtGui.QColor(125, 115, 202), \"#7d73ca\"],\n", + " \"yellow\": [QtGui.QColor(211, 89, 162), \"#d359a2\"],\n", + " \"orange\": [QtGui.QColor(255, 99, 97), \"#ff6361\"],\n", + " \"red\": [QtGui.QColor(255, 166, 0), \"#ffa600\"],\n", + " \"white\": [QtGui.QColor(\"white\"), \"#ffffff\"],\n", + " }\n", + " self.previous_design = \"\"\n", + " self.previous_project = \"\"\n", + "\n", + " # Set the legend tables to stretch resize mode\n", + " header = self.protection_legend_table.horizontalHeader()\n", + " v_header = self.protection_legend_table.verticalHeader()\n", + "\n", + " header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + "\n", + " header = self.interference_legend_table.horizontalHeader()\n", + " v_header = self.interference_legend_table.verticalHeader()\n", + "\n", + " header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + " v_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeMode.Stretch)\n", + "\n", + " # Input validation for protection level legend table\n", + " self.delegate = DoubleDelegate(\n", + " decimals=2, values=values, max_power=1000, min_power=-200\n", + " )\n", + " self.protection_legend_table.setItemDelegateForColumn(0, self.delegate)\n", + " self.open_file_dialog()\n", + "\n", + " # ## Open file dialog and select project\n", + " #\n", + " # Open the file dialog for project selection and populate the design dropdown\n", + " # with all EMIT designs in the project.\n", + "\n", + " def open_file_dialog(self):\n", + " fname, _ = QtWidgets.QFileDialog.getOpenFileName(\n", + " self,\n", + " \"Select EMIT Project\",\n", + " \"\",\n", + " \"Ansys Electronics Desktop Files (*.aedt)\",\n", + " )\n", + " if fname:\n", + " self.file_path_box.setText(fname)\n", + "\n", + " # Close previous project and open specified one\n", + " if self.emitapp is not None:\n", + " self.emitapp.close_project()\n", + " self.emitapp = None\n", + " desktop_proj = desktop.load_project(self.file_path_box.text())\n", + "\n", + " # check for an empty project (i.e. no designs)\n", + " if isinstance(desktop_proj, bool):\n", + " self.file_path_box.setText(\"\")\n", + " msg = QtWidgets.QMessageBox()\n", + " msg.setWindowTitle(\"Error: Project missing designs.\")\n", + " msg.setText(\n", + " \"The selected project has no designs. Projects must have at least \"\n", + " \"one EMIT design. See AEDT log for more information.\"\n", + " )\n", + " x = msg.exec()\n", + " return\n", + "\n", + " # Check if project is already open\n", + " if desktop_proj.lock_file == None:\n", + " msg = QtWidgets.QMessageBox()\n", + " msg.setWindowTitle(\"Error: Project already open\")\n", + " msg.setText(\n", + " \"Project is locked. Close or remove the lock before proceeding. See AEDT log for more information.\"\n", + " )\n", + " x = msg.exec()\n", + " return\n", + "\n", + " # Populate design dropdown with all design names\n", + " designs = desktop_proj.design_list\n", + " emit_designs = []\n", + " self.populating_dropdown = True\n", + " self.design_name_dropdown.clear()\n", + " self.populating_dropdown = False\n", + " for d in designs:\n", + " design_type = desktop.design_type(desktop_proj.project_name, d)\n", + " if design_type == \"EMIT\":\n", + " emit_designs.append(d)\n", + "\n", + " # Add warning if no EMIT design\n", + " # NOTE: This should never happen because loading a project without an EMIT design\n", + " # should add a blank EMIT design\n", + " self.warning_label.setHidden(True)\n", + " if len(emit_designs) == 0:\n", + " self.warning_label.setText(\n", + " \"Warning: The project must contain at least one EMIT design.\"\n", + " )\n", + " self.warning_label.setHidden(False)\n", + " return\n", + "\n", + " self.populating_dropdown = True\n", + " self.design_name_dropdown.addItems(emit_designs)\n", + " self.populating_dropdown = False\n", + " self.emitapp = get_pyaedt_app(desktop_proj.project_name, emit_designs[0])\n", + " self.design_name_dropdown.setCurrentIndex(0)\n", + "\n", + " # Check for at least 2 radios\n", + " radios = self.emitapp.modeler.components.get_radios()\n", + " self.warning_label.setHidden(True)\n", + " if len(radios) < 2:\n", + " self.warning_label.setText(\n", + " \"Warning: The selected design must contain at least two radios.\"\n", + " )\n", + " self.warning_label.setHidden(False)\n", + "\n", + " if self.radio_specific_levels.isEnabled():\n", + " self.radio_specific_levels.setChecked(False)\n", + " self.radio_dropdown.clear()\n", + " self.radio_dropdown.setEnabled(False)\n", + " self.protection_levels = {}\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " self.protection_levels[\"Global\"] = values\n", + "\n", + " self.radio_specific_levels.setEnabled(True)\n", + " self.protection_results_btn.setEnabled(True)\n", + " self.interference_results_btn.setEnabled(True)\n", + "\n", + " # ### Change design selection\n", + " #\n", + " # Refresh the warning messages when the selected design changes\n", + "\n", + " def design_dropdown_changed(self):\n", + " if self.populating_dropdown:\n", + " # Don't load design's on initial project load\n", + " return\n", + "\n", + " design_name = self.design_name_dropdown.currentText()\n", + " self.emitapp = get_pyaedt_app(self.emitapp.project_name, design_name)\n", + " # Check for at least 2 radios\n", + " radios = self.emitapp.modeler.components.get_radios()\n", + " self.warning_label.setHidden(True)\n", + " if len(radios) < 2:\n", + " self.warning_label.setText(\n", + " \"Warning: The selected design must contain at least two radios.\"\n", + " )\n", + " self.warning_label.setHidden(False)\n", + "\n", + " # Clear the table if the design is changed\n", + " self.clear_table()\n", + "\n", + " # ### Enable radio specific protection levels\n", + " #\n", + " # Activate radio selection dropdown and initialize dictionary to store protection levels\n", + " # when the radio-specific level dropdown is checked.\n", + "\n", + " def radio_specific(self):\n", + " self.radio_dropdown.setEnabled(self.radio_specific_levels.isChecked())\n", + " self.radio_dropdown.clear()\n", + " if self.radio_dropdown.isEnabled():\n", + " self.emitapp.set_active_design(self.design_name_dropdown.currentText())\n", + " radios = self.emitapp.modeler.components.get_radios()\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " for radio in radios:\n", + " if radios[radio].has_rx_channels():\n", + " self.protection_levels[radio] = values\n", + " self.radio_dropdown.addItem(radio)\n", + " else:\n", + " self.radio_dropdown.clear()\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " self.protection_levels[\"Global\"] = values\n", + " self.global_protection_level = not self.radio_specific_levels.isChecked()\n", + "\n", + " # ### Update legend table\n", + " #\n", + " # Update shown legend table values when the radio dropdown value changes.\n", + "\n", + " def radio_dropdown_changed(self):\n", + " if self.radio_dropdown.isEnabled():\n", + " self.changing = True\n", + " for row in range(self.protection_legend_table.rowCount()):\n", + " item = self.protection_legend_table.item(row, 0)\n", + " item.setText(\n", + " str(self.protection_levels[self.radio_dropdown.currentText()][row])\n", + " )\n", + " self.changing = False\n", + " # update the validator so min/max for each row is properly set\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " self.delegate.update_values(values)\n", + "\n", + " # ### Save legend table values\n", + " #\n", + " # Save inputted radio protection level threshold values every time one is changed\n", + " # in the legend table.\n", + "\n", + " def table_changed(self):\n", + " if self.changing == False:\n", + " values = [\n", + " float(self.protection_legend_table.item(row, 0).text())\n", + " for row in range(self.protection_legend_table.rowCount())\n", + " ]\n", + " if self.radio_dropdown.currentText() == \"\":\n", + " index = \"Global\"\n", + " else:\n", + " index = self.radio_dropdown.currentText()\n", + " self.protection_levels[index] = values\n", + " self.delegate.update_values(values)\n", + "\n", + " # ### Save scenario matrix to as PNG file\n", + " #\n", + " # Save the scenario matrix table as a PNG file.\n", + "\n", + " def save_image(self):\n", + " if self.tab_widget.currentIndex() == 0:\n", + " table = self.protection_matrix\n", + " else:\n", + " table = self.interference_matrix\n", + "\n", + " fname, _ = QtWidgets.QFileDialog.getSaveFileName(\n", + " self, \"Save Scenario Matrix\", \"Scenario Matrix\", \"png (*.png)\"\n", + " )\n", + " if fname:\n", + " image = QtGui.QImage(table.size(), QtGui.QImage.Format_ARGB32)\n", + " table.render(image)\n", + " image.save(fname)\n", + "\n", + " # ### Save scenario matrix to Excel file\n", + " #\n", + " # Write the scenario matrix results to an Excel file with color coding.\n", + "\n", + " def save_results_excel(self):\n", + " defaultName = \"\"\n", + " if self.tab_widget.currentIndex() == 0:\n", + " table = self.protection_matrix\n", + " defaultName = \"Protection Level Classification\"\n", + " else:\n", + " table = self.interference_matrix\n", + " defaultName = \"Interference Type Classification\"\n", + "\n", + " fname, _ = QtWidgets.QFileDialog.getSaveFileName(\n", + " self, \"Save Scenario Matrix\", defaultName, \"xlsx (*.xlsx)\"\n", + " )\n", + "\n", + " if fname:\n", + " workbook = openpyxl.Workbook()\n", + " worksheet = workbook.active\n", + " header = self.tx_radios[:]\n", + " header.insert(0, \"Tx/Rx\")\n", + " worksheet.append(header)\n", + " for row in range(2, table.rowCount() + 2):\n", + " worksheet.cell(row=row, column=1, value=str(self.rx_radios[row - 2]))\n", + " for col in range(2, table.columnCount() + 2):\n", + " text = str(table.item(row - 2, col - 2).text())\n", + " worksheet.cell(row=row, column=col, value=text)\n", + " cell = worksheet.cell(row, col)\n", + " cell.fill = PatternFill(\n", + " start_color=self.color_dict[self.all_colors[col - 2][row - 2]][\n", + " 1\n", + " ][1:],\n", + " end_color=self.color_dict[self.all_colors[col - 2][row - 2]][1][\n", + " 1:\n", + " ],\n", + " fill_type=\"solid\",\n", + " )\n", + " workbook.save(fname)\n", + "\n", + " # ### Run interference type simulation\n", + " #\n", + " # Run interference type simulation and classify results.\n", + "\n", + " def interference_results(self):\n", + " # Initialize filter check marks and expected filter results\n", + " self.interference_checks = [\n", + " self.in_in_check.isChecked(),\n", + " self.out_in_check.isChecked(),\n", + " self.in_out_check.isChecked(),\n", + " self.out_out_check.isChecked(),\n", + " ]\n", + "\n", + " self.interference_filters = [\n", + " \"TxFundamental:In-band\",\n", + " [\"TxHarmonic/Spurious:In-band\", \"Intermod:In-band\", \"Broadband:In-band\"],\n", + " \"TxFundamental:Out-of-band\",\n", + " [\n", + " \"TxHarmonic/Spurious:Out-of-band\",\n", + " \"Intermod:Out-of-band\",\n", + " \"Broadband:Out-of-band\",\n", + " ],\n", + " ]\n", + "\n", + " # Create list of problem types to analyze according to inputted filters\n", + " filter = [\n", + " i\n", + " for (i, v) in zip(self.interference_filters, self.interference_checks)\n", + " if v\n", + " ]\n", + "\n", + " if (\n", + " self.file_path_box.text() != \"\"\n", + " and self.design_name_dropdown.currentText() != \"\"\n", + " ):\n", + " if (\n", + " self.previous_design != self.design_name_dropdown.currentText()\n", + " or self.previous_project != self.file_path_box.text()\n", + " ):\n", + " self.previous_design = self.design_name_dropdown.currentText()\n", + " self.previous_project = self.file_path_box.text()\n", + " self.emitapp.set_active_design(self.design_name_dropdown.currentText())\n", + "\n", + " # Check if file is read-only\n", + " if self.emitapp.save_project() == False:\n", + " msg = QtWidgets.QMessageBox()\n", + " msg.setWindowTitle(\"Writing Error\")\n", + " msg.setText(\n", + " \"An error occurred while writing to the file. Is it readonly? Disk full? See AEDT log for more information.\"\n", + " )\n", + " x = msg.exec()\n", + " return\n", + "\n", + " # Get results and radios\n", + " self.rev = self.emitapp.results.analyze()\n", + " self.tx_interferer = InterfererType().TRANSMITTERS\n", + " self.rx_radios = self.rev.get_receiver_names()\n", + " self.tx_radios = self.rev.get_interferer_names(self.tx_interferer)\n", + "\n", + " # Check if design is valid\n", + " if self.tx_radios is None or self.rx_radios is None:\n", + " return\n", + "\n", + " # Classify the interference\n", + " # Iterate over all the transmitters and receivers and compute the power\n", + " # at the input to each receiver due to each of the transmitters. Compute\n", + " # which, if any, type of interference occurred.\n", + " domain = self.emitapp.results.interaction_domain()\n", + " (\n", + " self.all_colors,\n", + " self.power_matrix,\n", + " ) = self.rev.interference_type_classification(\n", + " domain, use_filter=True, filter_list=filter\n", + " )\n", + "\n", + " # Save project and plot results on table widget\n", + " self.emitapp.save_project()\n", + " self.populate_table()\n", + "\n", + " # ### Run protection level simulation\n", + " #\n", + " # Run protection level simulation and classify results according to inputted\n", + " # threshold levels.\n", + "\n", + " def protection_results(self):\n", + " # Initialize filter check marks and expected filter results\n", + " self.protection_checks = [\n", + " self.damage_check.isChecked(),\n", + " self.overload_check.isChecked(),\n", + " self.intermodulation_check.isChecked(),\n", + " self.desensitization_check.isChecked(),\n", + " ]\n", + "\n", + " self.protection_filters = [\n", + " \"damage\",\n", + " \"overload\",\n", + " \"intermodulation\",\n", + " \"desensitization\",\n", + " ]\n", + "\n", + " filter = [\n", + " i for (i, v) in zip(self.protection_filters, self.protection_checks) if v\n", + " ]\n", + "\n", + " if (\n", + " self.file_path_box.text() != \"\"\n", + " and self.design_name_dropdown.currentText() != \"\"\n", + " ):\n", + " if (\n", + " self.previous_design != self.design_name_dropdown.currentText()\n", + " or self.previous_project != self.file_path_box.text()\n", + " ):\n", + " self.previous_design = self.design_name_dropdown.currentText()\n", + " self.previous_project = self.file_path_box.text()\n", + " self.emitapp.set_active_design(self.design_name_dropdown.currentText())\n", + "\n", + " # Check if file is read-only\n", + " if self.emitapp.save_project() == False:\n", + " msg = QtWidgets.QMessageBox()\n", + " msg.setWindowTitle(\"Writing Error\")\n", + " msg.setText(\n", + " \"An error occurred while writing to the file. Is it readonly? Disk full? See AEDT log for more information.\"\n", + " )\n", + " x = msg.exec()\n", + " return\n", + "\n", + " # Get results and design radios\n", + " self.tx_interferer = InterfererType().TRANSMITTERS\n", + " self.rev = self.emitapp.results.analyze()\n", + " self.rx_radios = self.rev.get_receiver_names()\n", + " self.tx_radios = self.rev.get_interferer_names(self.tx_interferer)\n", + "\n", + " # Check if there are radios in the design\n", + " if self.tx_radios is None or self.rx_radios is None:\n", + " return\n", + "\n", + " domain = self.emitapp.results.interaction_domain()\n", + " (\n", + " self.all_colors,\n", + " self.power_matrix,\n", + " ) = self.rev.protection_level_classification(\n", + " domain,\n", + " self.global_protection_level,\n", + " self.protection_levels[\"Global\"],\n", + " self.protection_levels,\n", + " use_filter=True,\n", + " filter_list=filter,\n", + " )\n", + "\n", + " self.populate_table()\n", + "\n", + " # ### Populate the scenario matrix\n", + " #\n", + " # Create a scenario matrix view with the transmitters defined across the top\n", + " # and receivers down the left-most column.\n", + "\n", + " def populate_table(self):\n", + " if self.tab_widget.currentIndex() == 0:\n", + " table = self.protection_matrix\n", + " button = self.protection_export_btn\n", + " img_btn = self.protection_save_img_btn\n", + " else:\n", + " table = self.interference_matrix\n", + " button = self.interference_export_btn\n", + " img_btn = self.interference_save_img_btn\n", + "\n", + " num_cols = len(self.all_colors)\n", + " num_rows = len(self.all_colors[0])\n", + " table.setColumnCount(num_cols)\n", + " table.setRowCount(num_rows)\n", + " table.setVerticalHeaderLabels(self.rx_radios)\n", + " table.setHorizontalHeaderLabels(self.tx_radios)\n", + "\n", + " for col in range(num_cols):\n", + " for row in range(num_rows):\n", + " item = QtWidgets.QTableWidgetItem(str(self.power_matrix[col][row]))\n", + " table.setItem(row, col, item)\n", + " cell = table.item(row, col)\n", + " cell.setBackground(self.color_dict[self.all_colors[col][row]][0])\n", + "\n", + " button.setEnabled(True)\n", + " img_btn.setEnabled(True)\n", + "\n", + " def clear_table(self):\n", + " # get the table/buttons based on current tab\n", + " if self.tab_widget.currentIndex() == 0:\n", + " table = self.protection_matrix\n", + " button = self.protection_export_btn\n", + " img_btn = self.protection_save_img_btn\n", + " else:\n", + " table = self.interference_matrix\n", + " button = self.interference_export_btn\n", + " img_btn = self.interference_save_img_btn\n", + "\n", + " # disable export options\n", + " button.setEnabled(False)\n", + " img_btn.setEnabled(False)\n", + "\n", + " # clear the table\n", + " table.setColumnCount(0)\n", + " table.setRowCount(0)\n", + "\n", + " # ### GUI closing event\n", + " #\n", + " # Close AEDT if the GUI is closed.\n", + " def closeEvent(self, event):\n", + " msg = QtWidgets.QMessageBox()\n", + " msg.setWindowTitle(\"Closing GUI\")\n", + " msg.setText(\"Closing AEDT. Wait for the GUI to close on its own.\")\n", + " x = msg.exec()\n", + " if self.emitapp:\n", + " self.emitapp.close_project()\n", + " self.emitapp.close_desktop()\n", + " else:\n", + " desktop.release_desktop(True, True)" + ] + }, + { + "cell_type": "markdown", + "id": "4794bd13", + "metadata": {}, + "source": [ + "## Run GUI\n", + "\n", + "Run the GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79c51989", + "metadata": {}, + "outputs": [], + "source": [ + "if __name__ == \"__main__\":\n", + " app = QtWidgets.QApplication([])\n", + " window = MainWindow()\n", + " window.show()\n", + " app.exec()\n", + "else:\n", + " desktop.release_desktop(True, True)" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/interferences/protection.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/interferences/protection.ipynb.txt new file mode 100644 index 00000000..39d75eb7 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/interferences/protection.ipynb.txt @@ -0,0 +1,546 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6036e925", + "metadata": {}, + "source": [ + "# Compute receiver protection levels\n", + "\n", + "This example shows how to open an AEDT project with\n", + "an EMIT design and analyze the results to determine if the received\n", + "power at the input to each receiver exceeds the specified protection\n", + "levels.\n", + "\n", + "Keywords: **EMIT**, **protection levels**." + ] + }, + { + "cell_type": "markdown", + "id": "abe1db39", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "862385bc", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c912455b", + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.graph_objects as go\n", + "from ansys.aedt.core import Emit" + ] + }, + { + "cell_type": "markdown", + "id": "d3d6002f", + "metadata": {}, + "source": [ + "from ansys.aedt.core.emit_core.emit_constants import \\\n", + " InterfererType # noqa: F401" + ] + }, + { + "cell_type": "markdown", + "id": "ef2d8182", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70e9a4c4", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "91c380e1", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "978af829", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "d75b8f06", + "metadata": {}, + "source": [ + "## Launch AEDT with EMIT\n", + "\n", + "Launch AEDT with EMIT. The ``Desktop`` class initializes AEDT and starts it\n", + "on the specified version and in the specified graphical mode.\n", + "\n", + "Check that the correct version of EMIT is installed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e481027e", + "metadata": {}, + "outputs": [], + "source": [ + "if AEDT_VERSION <= \"2023.1\":\n", + " print(\"Warning: This example requires AEDT 2023.2 or later.\")\n", + " sys.exit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13099a8c", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"emit.aedt\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a147ea02", + "metadata": {}, + "outputs": [], + "source": [ + "emitapp = Emit(\n", + " non_graphical=NG_MODE, new_desktop=True, project=project_name, version=AEDT_VERSION\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3cb08c6d", + "metadata": {}, + "source": [ + "## Specify protection levels\n", + "\n", + "The protection levels are specified in dBm.\n", + "If the damage threshold is exceeded, permanent damage to the receiver front\n", + "end may occur.\n", + "Exceeding the overload threshold severely densensitizes the receiver.\n", + "Exceeding the intermod threshold can drive the victim receiver into non-linear\n", + "operation, where it operates as a mixer.\n", + "Exceeding the desense threshold reduces the signal-to-noise ratio and can\n", + "reduce the maximum range, maximum bandwidth, and/or the overall link quality." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b3f240f", + "metadata": {}, + "outputs": [], + "source": [ + "header_color = \"grey\"\n", + "damage_threshold = 30\n", + "overload_threshold = -4\n", + "intermod_threshold = -30\n", + "desense_threshold = -104\n", + "\n", + "protection_levels = [\n", + " damage_threshold,\n", + " overload_threshold,\n", + " intermod_threshold,\n", + " desense_threshold,\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "7fd2e9d3", + "metadata": {}, + "source": [ + "## Create and connect EMIT components\n", + "\n", + "Set up the scenario with radios connected to antennas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd7796ca", + "metadata": {}, + "outputs": [], + "source": [ + "bluetooth, blue_ant = emitapp.modeler.components.create_radio_antenna(\n", + " \"Bluetooth Low Energy (LE)\", \"Bluetooth\"\n", + ")\n", + "gps, gps_ant = emitapp.modeler.components.create_radio_antenna(\"GPS Receiver\", \"GPS\")\n", + "wifi, wifi_ant = emitapp.modeler.components.create_radio_antenna(\n", + " \"WiFi - 802.11-2012\", \"WiFi\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "95720730", + "metadata": {}, + "source": [ + "## Configure the radios\n", + "\n", + "Enable the HR-DSSS bands for the Wi-Fi radio and set the power level\n", + "for all transmit bands to -20 dBm." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e129153c", + "metadata": {}, + "outputs": [], + "source": [ + "bands = wifi.bands()\n", + "for band in bands:\n", + " if \"HR-DSSS\" in band.node_name:\n", + " if \"Ch 1-13\" in band.node_name:\n", + " band.enabled = True\n", + " band.set_band_power_level(-20)\n", + "\n", + "# Reduce the bluetooth transmit power\n", + "bands = bluetooth.bands()\n", + "for band in bands:\n", + " band.set_band_power_level(-20)\n", + "\n", + "\n", + "def get_radio_node(radio_name):\n", + " \"\"\"Get the radio node that matches the\n", + " given radio name.\n", + "\n", + " Arguments:\n", + " radio_name: String name of the radio.\n", + "\n", + " Returns: Instance of the radio.\n", + " \"\"\"\n", + " if gps.name == radio_name:\n", + " radio = gps\n", + " elif bluetooth.name == radio_name:\n", + " radio = bluetooth\n", + " else:\n", + " radio = wifi\n", + " return radio\n", + "\n", + "\n", + "bands = gps.bands()\n", + "for band in bands:\n", + " for child in band.children:\n", + " if \"L2 P(Y)\" in band.node_name:\n", + " band.enabled = True\n", + " else:\n", + " band.enabled = False" + ] + }, + { + "cell_type": "markdown", + "id": "76f0fcbb", + "metadata": {}, + "source": [ + "## Load the results set\n", + "\n", + "Create a results revision and load it for analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa077843", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "rev = emitapp.results.analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "03455e52", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Create a legend\n", + "\n", + "Create a legend, defining the thresholds and colors used to display the results of\n", + "the protection level analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a99604a", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "def create_legend_table():\n", + " \"\"\"Create a table showing the defined protection levels.\"\"\"\n", + " protectionLevels = [\n", + " \">{} dBm\".format(damage_threshold),\n", + " \">{} dBm\".format(overload_threshold),\n", + " \">{} dBm\".format(intermod_threshold),\n", + " \">{} dBm\".format(desense_threshold),\n", + " ]\n", + " fig = go.Figure(\n", + " data=[\n", + " go.Table(\n", + " header=dict(\n", + " values=[\"Interference\", \"Power Level Threshold\"],\n", + " line_color=\"darkslategray\",\n", + " fill_color=header_color,\n", + " align=[\"left\", \"center\"],\n", + " font=dict(color=\"white\", size=16),\n", + " ),\n", + " cells=dict(\n", + " values=[\n", + " [\"Damage\", \"Overload\", \"Intermodulation\", \"Clear\"],\n", + " protectionLevels,\n", + " ],\n", + " line_color=\"darkslategray\",\n", + " fill_color=[\"white\", [\"red\", \"orange\", \"yellow\", \"green\"]],\n", + " align=[\"left\", \"center\"],\n", + " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", + " ),\n", + " )\n", + " ]\n", + " )\n", + " fig.update_layout(\n", + " title=dict(\n", + " text=\"Protection Levels (dBm)\",\n", + " font=dict(color=\"darkslategray\", size=20),\n", + " x=0.5,\n", + " ),\n", + " width=600,\n", + " )\n", + " fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "497ecf27", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Create a scenario matrix view\n", + "\n", + "Create a scenario matrix view with the transmitters defined across the top\n", + "and receivers down the left-most column. The power at the input to each\n", + "receiver is shown in each cell of the matrix and color-coded based on the\n", + "protection level thresholds defined." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "996ceebd", + "metadata": {}, + "outputs": [], + "source": [ + "def create_scenario_view(emis, colors, tx_radios, rx_radios):\n", + " \"\"\"Create a scenario matrix-like table with the higher received\n", + " power for each Tx-Rx radio combination. The colors\n", + " used for the scenario matrix view are based on the highest\n", + " protection level that the received power exceeds.\"\"\"\n", + " fig = go.Figure(\n", + " data=[\n", + " go.Table(\n", + " header=dict(\n", + " values=[\n", + " \"Tx/Rx\",\n", + " \"{}\".format(tx_radios[0]),\n", + " \"{}\".format(tx_radios[1]),\n", + " ],\n", + " line_color=\"darkslategray\",\n", + " fill_color=header_color,\n", + " align=[\"left\", \"center\"],\n", + " font=dict(color=\"white\", size=16),\n", + " ),\n", + " cells=dict(\n", + " values=[rx_radios, emis[0], emis[1]],\n", + " line_color=\"darkslategray\",\n", + " fill_color=[\"white\", colors[0], colors[1]],\n", + " align=[\"left\", \"center\"],\n", + " font=dict(color=[\"darkslategray\", \"black\"], size=15),\n", + " ),\n", + " )\n", + " ]\n", + " )\n", + " fig.update_layout(\n", + " title=dict(\n", + " text=\"Protection Levels (dBm)\",\n", + " font=dict(color=\"darkslategray\", size=20),\n", + " x=0.5,\n", + " ),\n", + " width=600,\n", + " )\n", + " fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "7dd44ebc", + "metadata": {}, + "source": [ + "## Get all the radios in the project\n", + "\n", + "Get lists of all transmitters and receivers in the project." + ] + }, + { + "cell_type": "markdown", + "id": "078e0f45", + "metadata": {}, + "source": [ + "> **Note:** You can uncomment the following code.\n", + "\n", + "rev = emitapp.results.current_revision\n", + "rx_radios = rev.get_receiver_names()\n", + "tx_radios = rev.get_interferer_names(InterfererType.TRANSMITTERS)\n", + "domain = emitapp.results.interaction_domain()" + ] + }, + { + "cell_type": "markdown", + "id": "87432227", + "metadata": {}, + "source": [ + "## Classify the results\n", + "\n", + "Iterate over all the transmitters and receivers and compute the power\n", + "at the input to each receiver due to each of the transmitters. Computes\n", + "which protection levels are exceeded by these power levels, if any." + ] + }, + { + "cell_type": "markdown", + "id": "af408227", + "metadata": {}, + "source": [ + "> **Note:** Your ability to uncomment the following code depends on whether you uncommented the earlier code.\n", + "\n", + "power_matrix = []\n", + "all_colors = []" + ] + }, + { + "cell_type": "markdown", + "id": "54678e42", + "metadata": {}, + "source": [ + "all_colors, power_matrix = rev.protection_level_classification(\n", + " domain, global_levels=protection_levels\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a3e96701", + "metadata": {}, + "source": [ + "## Create a scenario matrix-like view for the protection levels\n", + "create_scenario_view(power_matrix, all_colors, tx_radios, rx_radios)" + ] + }, + { + "cell_type": "markdown", + "id": "41441bd3", + "metadata": {}, + "source": [ + "## Create a legend for the protection levels\n", + "create_legend_table()" + ] + }, + { + "cell_type": "markdown", + "id": "049f4189", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed6a71a0", + "metadata": {}, + "outputs": [], + "source": [ + "emitapp.save_project()\n", + "emitapp.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e4c07518", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "242e903f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/city.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/city.ipynb.txt new file mode 100644 index 00000000..9f8b9147 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/city.ipynb.txt @@ -0,0 +1,245 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6350543c", + "metadata": {}, + "source": [ + "# Geometry import from maps\n", + "\n", + "This example shows how to use PyAEDT to create an HFSS SBR+ project from\n", + "OpenStreetMap.\n", + "\n", + "Keywords: **HFSS**, **SBR+**, **city**." + ] + }, + { + "cell_type": "markdown", + "id": "4ad8d71c", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports and set up the local path to the PyAEDT\n", + "directory path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "274cc57d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "457a4f13", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "a897e8d4", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bfff382e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "ad381f6c", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76dde39e", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "f0ef42c3", + "metadata": {}, + "source": [ + "## Launch HFSS and open project\n", + "\n", + "Launch HFSS and open the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ad3440d", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"city.aedt\")\n", + "app = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " design=\"Ansys\",\n", + " solution_type=\"SBR+\",\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4cc5163a", + "metadata": {}, + "source": [ + "## Define location to import\n", + "\n", + "Define the latitude and longitude of the location to import." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34f66c6c", + "metadata": {}, + "outputs": [], + "source": [ + "ansys_home = [40.273726, -80.168269]" + ] + }, + { + "cell_type": "markdown", + "id": "7856cd6b", + "metadata": {}, + "source": [ + "## Generate map and import\n", + "\n", + "Assign boundaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f0e991f", + "metadata": {}, + "outputs": [], + "source": [ + "app.modeler.import_from_openstreet_map(\n", + " ansys_home,\n", + " terrain_radius=250,\n", + " road_step=3,\n", + " plot_before_importing=False,\n", + " import_in_aedt=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3027193f", + "metadata": {}, + "source": [ + "## Plot model\n", + "\n", + "Plot the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccb2c472", + "metadata": {}, + "outputs": [], + "source": [ + "plot_obj = app.plot(show=False, plot_air_objects=True)\n", + "plot_obj.background_color = [153, 203, 255]\n", + "plot_obj.zoom = 1.5\n", + "plot_obj.show_grid = False\n", + "plot_obj.show_axes = False\n", + "plot_obj.bounding_box = False\n", + "plot_obj.plot(os.path.join(temp_folder.name, \"Source.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "d86157d2", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a166e9e0", + "metadata": {}, + "outputs": [], + "source": [ + "app.save_project()\n", + "app.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "0a4286b4", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95ffa968", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/doppler.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/doppler.ipynb.txt new file mode 100644 index 00000000..10cda82f --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/doppler.ipynb.txt @@ -0,0 +1,416 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a826356d", + "metadata": {}, + "source": [ + "# Doppler setup\n", + "\n", + "This example shows how to use PyAEDT to create a multipart scenario in HFSS SBR+\n", + "and set up a doppler analysis.\n", + "\n", + "Keywords: **HFSS**, **SBR+**, **doppler**." + ] + }, + { + "cell_type": "markdown", + "id": "462812b9", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38422d19", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02f07c9c", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "50a48f87", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1df64fae", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "dfd56680", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87b32333", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "ed2be6d6", + "metadata": {}, + "source": [ + "## Download 3D component\n", + "Download the 3D component that is needed to run the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f96aa4d7", + "metadata": {}, + "outputs": [], + "source": [ + "library_path = ansys.aedt.core.downloads.download_multiparts(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b5a5ed33", + "metadata": {}, + "source": [ + "## Launch HFSS and open project\n", + "\n", + "Launch HFSS and open the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4163e645", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"doppler.aedt\")\n", + "app = ansys.aedt.core.Hfss(\n", + " version=AEDT_VERSION,\n", + " solution_type=\"SBR+\",\n", + " new_desktop=True,\n", + " project=project_name,\n", + " close_on_exit=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9665f9a6", + "metadata": {}, + "source": [ + "Creation of the \"actors\" in the scene is comprised of many editing steps. Disabling the autosave option helps\n", + "avoid delays that occur while the project is being saved." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa66e3d4", + "metadata": {}, + "outputs": [], + "source": [ + "app.autosave_disable()" + ] + }, + { + "cell_type": "markdown", + "id": "603e11e4", + "metadata": {}, + "source": [ + "## Save project and rename design\n", + "\n", + "Save the project to the temporary folder and rename the design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4886935d", + "metadata": {}, + "outputs": [], + "source": [ + "design = \"doppler_sbr\"\n", + "app.rename_design(design)\n", + "app.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "b5b79df9", + "metadata": {}, + "source": [ + "## Set up library paths\n", + "\n", + "Specify the location of 3D components used to create the scene." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b232e76", + "metadata": {}, + "outputs": [], + "source": [ + "actor_lib = os.path.join(library_path, \"actor_library\")\n", + "env_lib = os.path.join(library_path, \"environment_library\")\n", + "radar_lib = os.path.join(library_path, \"radar_modules\")\n", + "env_folder = os.path.join(env_lib, \"road1\")\n", + "person_folder = os.path.join(actor_lib, \"person3\")\n", + "car_folder = os.path.join(actor_lib, \"vehicle1\")\n", + "bike_folder = os.path.join(actor_lib, \"bike1\")\n", + "bird_folder = os.path.join(actor_lib, \"bird1\")" + ] + }, + { + "cell_type": "markdown", + "id": "5834556e", + "metadata": {}, + "source": [ + "## Define environment\n", + "\n", + "Define the background environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c89bca79", + "metadata": {}, + "outputs": [], + "source": [ + "road1 = app.modeler.add_environment(input_dir=env_folder, name=\"Bari\")\n", + "prim = app.modeler" + ] + }, + { + "cell_type": "markdown", + "id": "fe28c0c6", + "metadata": {}, + "source": [ + "## Place actors\n", + "\n", + "Place actors in the environment. This code places persons, birds, bikes, and cars\n", + "in the environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6314f06c", + "metadata": {}, + "outputs": [], + "source": [ + "person1 = app.modeler.add_person(\n", + " input_dir=person_folder,\n", + " speed=1.0,\n", + " global_offset=[25, 1.5, 0],\n", + " yaw=180,\n", + " name=\"Massimo\",\n", + ")\n", + "person2 = app.modeler.add_person(\n", + " input_dir=person_folder,\n", + " speed=1.0,\n", + " global_offset=[25, 2.5, 0],\n", + " yaw=180,\n", + " name=\"Devin\",\n", + ")\n", + "car1 = app.modeler.add_vehicle(\n", + " input_dir=car_folder, speed=8.7, global_offset=[3, -2.5, 0], name=\"LuxuryCar\"\n", + ")\n", + "bike1 = app.modeler.add_vehicle(\n", + " input_dir=bike_folder,\n", + " speed=2.1,\n", + " global_offset=[24, 3.6, 0],\n", + " yaw=180,\n", + " name=\"Alberto_in_bike\",\n", + ")\n", + "bird1 = app.modeler.add_bird(\n", + " input_dir=bird_folder,\n", + " speed=1.0,\n", + " global_offset=[19, 4, 3],\n", + " yaw=120,\n", + " pitch=-5,\n", + " flapping_rate=30,\n", + " name=\"Pigeon\",\n", + ")\n", + "bird2 = app.modeler.add_bird(\n", + " input_dir=bird_folder,\n", + " speed=1.0,\n", + " global_offset=[6, 2, 3],\n", + " yaw=-60,\n", + " pitch=10,\n", + " name=\"Eagle\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e65e5b40", + "metadata": {}, + "source": [ + "## Place radar\n", + "\n", + "Place radar on the car. The radar is created relative to the car's coordinate\n", + "system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fba7f55b", + "metadata": {}, + "outputs": [], + "source": [ + "radar1 = app.create_sbr_radar_from_json(\n", + " radar_file=radar_lib,\n", + " name=\"Example_1Tx_1Rx\",\n", + " offset=[2.57, 0, 0.54],\n", + " use_relative_cs=True,\n", + " relative_cs_name=car1.cs_name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c3199229", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create setup and validate it. The ``create_sbr_pulse_doppler_setup()`` method\n", + "creates a setup and a parametric sweep on the time variable with a\n", + "duration of two seconds. The step is computed automatically from CPI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96e46766", + "metadata": {}, + "outputs": [], + "source": [ + "setup, sweep = app.create_sbr_pulse_doppler_setup(sweep_time_duration=2)\n", + "app.set_sbr_current_sources_options()\n", + "app.validate_simple()" + ] + }, + { + "cell_type": "markdown", + "id": "619952b8", + "metadata": {}, + "source": [ + "## Solve and release AEDT\n", + "\n", + "Solve and release AEDT. To solve, uncomment the ``app.analyze_setup`` command\n", + "to activate the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0aa4447", + "metadata": {}, + "outputs": [], + "source": [ + "# app.analyze_setup(sweep.name)" + ] + }, + { + "cell_type": "markdown", + "id": "bead3976", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed6ff10a", + "metadata": {}, + "outputs": [], + "source": [ + "app.save_project()\n", + "app.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "74095213", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39184342", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/index.rst.txt b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/index.rst.txt new file mode 100644 index 00000000..9ffc6bbf --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/index.rst.txt @@ -0,0 +1,66 @@ +Large scenarios +~~~~~~~~~~~~~~~ +These examples use PyAEDT to show some general capabilities of HFSS SBR+ for large scenarios + +.. grid:: 2 + + .. grid-item-card:: Geometry import from maps + :padding: 2 2 2 2 + :link: city + :link-type: doc + + .. image:: _static/city.png + :alt: City + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an HFSS SBR+ project from OpenStreetMap. + + .. grid-item-card:: Doppler setup + :padding: 2 2 2 2 + :link: doppler + :link-type: doc + + .. image:: _static/doppler.png + :alt: Doppler + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a multipart scenario in HFSS SBR+ and set up a doppler analysis. + + .. grid-item-card:: Reflector + :padding: 2 2 2 2 + :link: reflector + :link-type: doc + + .. image:: _static/reflector.png + :alt: Reflector + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an HFSS SBR+ project from an HFSS antenna and run a simulation. + + .. grid-item-card:: HFSS to SBR+ time animation + :padding: 2 2 2 2 + :link: time_domain + :link-type: doc + + .. image:: _static/time_domain.png + :alt: SBR Time + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create an SBR+ time animation and save it to a GIF file. + + + .. toctree:: + :hidden: + + city + doppler + reflector + time_domain diff --git a/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/reflector.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/reflector.ipynb.txt new file mode 100644 index 00000000..bc7378eb --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/reflector.ipynb.txt @@ -0,0 +1,324 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "68e3c444", + "metadata": {}, + "source": [ + "# Reflector\n", + "\n", + "This example shows how to use PyAEDT to create an HFSS SBR+ project from an\n", + "HFSS antenna and run a simulation.\n", + "\n", + "Keywords: **HFSS**, **SBR+**, **reflector**." + ] + }, + { + "cell_type": "markdown", + "id": "749b8e92", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports and set up the local path to the path for the PyAEDT\n", + "directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e0611f7", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7e79fd6", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "d798c252", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88298fbc", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "8563cb93", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83337688", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "a8e7ca5c", + "metadata": {}, + "source": [ + "## Download project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21b2d884", + "metadata": {}, + "outputs": [], + "source": [ + "project_full_name = ansys.aedt.core.downloads.download_sbr(destination=temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "186bb806", + "metadata": {}, + "source": [ + "## Define designs\n", + "\n", + "Define two designs, one source and one target, with each design connected to\n", + "a different object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e12bcf3c", + "metadata": {}, + "outputs": [], + "source": [ + "target = ansys.aedt.core.Hfss(\n", + " project=project_full_name,\n", + " design=\"Cassegrain_\",\n", + " solution_type=\"SBR+\",\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")\n", + "\n", + "source = ansys.aedt.core.Hfss(\n", + " project=target.project_name,\n", + " design=\"feeder\",\n", + " version=AEDT_VERSION,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ea3caf38", + "metadata": {}, + "source": [ + "## Define linked antenna\n", + "\n", + "Define a linked antenna. This is HFSS far field applied to HFSS SBR+." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4cebe788", + "metadata": {}, + "outputs": [], + "source": [ + "target.create_sbr_linked_antenna(\n", + " source, target_cs=\"feederPosition\", field_type=\"farfield\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9a53851b", + "metadata": {}, + "source": [ + "## Assign boundaries\n", + "\n", + "Assign boundaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a781c590", + "metadata": {}, + "outputs": [], + "source": [ + "target.assign_perfecte_to_sheets([\"Reflector\", \"Subreflector\"])\n", + "target.mesh.assign_curvilinear_elements([\"Reflector\", \"Subreflector\"])" + ] + }, + { + "cell_type": "markdown", + "id": "044927fb", + "metadata": {}, + "source": [ + "## Create setup and solve\n", + "\n", + "Create a setup and solve it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e60a39a2", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = target.create_setup()\n", + "setup1.props[\"RadiationSetup\"] = \"ATK_3D\"\n", + "setup1.props[\"ComputeFarFields\"] = True\n", + "setup1.props[\"RayDensityPerWavelength\"] = 2\n", + "setup1.props[\"MaxNumberOfBounces\"] = 3\n", + "setup1[\"RangeType\"] = \"SinglePoints\"\n", + "setup1[\"RangeStart\"] = \"10GHz\"\n", + "target.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "f29d7211", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Plot results in AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e3c5be4", + "metadata": {}, + "outputs": [], + "source": [ + "variations = target.available_variations.nominal_w_values_dict\n", + "variations[\"Freq\"] = [\"10GHz\"]\n", + "variations[\"Theta\"] = [\"All\"]\n", + "variations[\"Phi\"] = [\"All\"]\n", + "target.post.create_report(\n", + " \"db(GainTotal)\",\n", + " target.nominal_adaptive,\n", + " variations=variations,\n", + " primary_sweep_variable=\"Theta\",\n", + " context=\"ATK_3D\",\n", + " report_category=\"Far Fields\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fd954417", + "metadata": {}, + "source": [ + "Plot results using Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5faa01c5", + "metadata": {}, + "outputs": [], + "source": [ + "solution = target.post.get_solution_data(\n", + " \"GainTotal\",\n", + " target.nominal_adaptive,\n", + " variations=variations,\n", + " primary_sweep_variable=\"Theta\",\n", + " context=\"ATK_3D\",\n", + " report_category=\"Far Fields\",\n", + ")\n", + "solution.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "c4a69104", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb22099d", + "metadata": {}, + "outputs": [], + "source": [ + "target.save_project()\n", + "target.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1c2d63fb", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8a250e9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/time_domain.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/time_domain.ipynb.txt new file mode 100644 index 00000000..5cdaaf92 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/large_scenarios/time_domain.ipynb.txt @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f1d3515d", + "metadata": {}, + "source": [ + "# HFSS to SBR+ time animation\n", + "\n", + "This example shows how to use PyAEDT to create an SBR+ time animation\n", + "and save it to a GIF file. This example works only on CPython.\n", + "\n", + "Keywords: **HFSS**, **SBR+**, **time domain**, **IFFT**." + ] + }, + { + "cell_type": "markdown", + "id": "37bbc629", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f4ffb73", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd3671b3", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Hfss, downloads" + ] + }, + { + "cell_type": "markdown", + "id": "6db230de", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72eaf096", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "f8f9ae56", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0729654b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "a664ea7e", + "metadata": {}, + "source": [ + "## Download project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f9ef3f3", + "metadata": {}, + "outputs": [], + "source": [ + "project_file = downloads.download_sbr_time(destination=temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "9adcbb0f", + "metadata": {}, + "source": [ + "## Launch HFSS and analyze" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c08fbaa", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = Hfss(\n", + " project=project_file,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68ae8a04", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "639b4e53", + "metadata": {}, + "source": [ + "## Get solution data\n", + "\n", + "Get solution data. After the simulation is performed, you can load solutions\n", + "in the ``solution_data`` object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "845833ff", + "metadata": {}, + "outputs": [], + "source": [ + "solution_data = hfss.post.get_solution_data(\n", + " expressions=[\"NearEX\", \"NearEY\", \"NearEZ\"],\n", + " variations={\"_u\": [\"All\"], \"_v\": [\"All\"], \"Freq\": [\"All\"]},\n", + " context=\"Near_Field\",\n", + " report_category=\"Near Fields\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e052241a", + "metadata": {}, + "source": [ + "## Compute IFFT\n", + "\n", + "Compute IFFT (Inverse Fast Fourier Transform)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59d34b9d", + "metadata": {}, + "outputs": [], + "source": [ + "t_matrix = solution_data.ifft(\"NearE\", window=True)" + ] + }, + { + "cell_type": "markdown", + "id": "79bbab34", + "metadata": {}, + "source": [ + "## Export IFFT to CSV file\n", + "\n", + "Export IFFT to a CSV file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "523f81c9", + "metadata": {}, + "outputs": [], + "source": [ + "frames_list_file = solution_data.ifft_to_file(\n", + " coord_system_center=[-0.15, 0, 0],\n", + " db_val=True,\n", + " csv_path=os.path.join(hfss.working_directory, \"csv\"),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "038f5617", + "metadata": {}, + "source": [ + "## Plot scene\n", + "\n", + "Plot the scene to create the time plot animation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d01ec9e2", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.post.plot_scene(\n", + " frames=frames_list_file,\n", + " gif_path=os.path.join(hfss.working_directory, \"animation.gif\"),\n", + " norm_index=15,\n", + " dy_rng=35,\n", + " show=False,\n", + " view=\"xy\",\n", + " zoom=1,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c61f4d78", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c3cb39f", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b9afc410", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2bf0b4e", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/antenna/patch.ipynb.txt b/version/dev/_sources/examples/high_frequency/antenna/patch.ipynb.txt new file mode 100644 index 00000000..9cbf5705 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/antenna/patch.ipynb.txt @@ -0,0 +1,275 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "97d37c04", + "metadata": {}, + "source": [ + "# Probe-fed patch antenna\n", + "\n", + "This example shows how to use the ``Stackup3D`` class\n", + "to create and analyze a patch antenna in HFSS.\n", + "\n", + "Note that the HFSS 3D Layout interface may offer advantages for\n", + "laminate structures such as the patch antenna.\n", + "\n", + "Keywords: **HFSS**, **terminal**, **antenna**., **patch**.\n", + "\n", + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "061e8a02", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c50794a3", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.modeler.advanced_cad.stackup_3d import Stackup3D" + ] + }, + { + "cell_type": "markdown", + "id": "9d4a8719", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da0736b2", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "38034960", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05409739", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "3edd459b", + "metadata": {}, + "source": [ + "## Launch HFSS\n", + "\n", + "Launch HFSS and change the length units." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3618fec", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"patch.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " solution_type=\"Terminal\",\n", + " design=\"patch\",\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " version=AEDT_VERSION,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ec22a64", + "metadata": {}, + "outputs": [], + "source": [ + "length_units = \"mm\"\n", + "freq_units = \"GHz\"\n", + "hfss.modeler.model_units = length_units" + ] + }, + { + "cell_type": "markdown", + "id": "1a051007", + "metadata": {}, + "source": [ + "## Create patch\n", + "\n", + "Create the patch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe58808d", + "metadata": {}, + "outputs": [], + "source": [ + "stackup = Stackup3D(hfss)\n", + "ground = stackup.add_ground_layer(\n", + " \"ground\", material=\"copper\", thickness=0.035, fill_material=\"air\"\n", + ")\n", + "dielectric = stackup.add_dielectric_layer(\n", + " \"dielectric\", thickness=\"0.5\" + length_units, material=\"Duroid (tm)\"\n", + ")\n", + "signal = stackup.add_signal_layer(\n", + " \"signal\", material=\"copper\", thickness=0.035, fill_material=\"air\"\n", + ")\n", + "patch = signal.add_patch(\n", + " patch_length=9.57, patch_width=9.25, patch_name=\"Patch\", frequency=1e10\n", + ")\n", + "\n", + "stackup.resize_around_element(patch)\n", + "pad_length = [3, 3, 3, 3, 3, 3] # Air bounding box buffer in mm.\n", + "region = hfss.modeler.create_region(pad_length, is_percentage=False)\n", + "hfss.assign_radiation_boundary_to_objects(region)\n", + "\n", + "patch.create_probe_port(ground, rel_x_offset=0.485)" + ] + }, + { + "cell_type": "markdown", + "id": "b1c1c8a9", + "metadata": {}, + "source": [ + "## Set up simulation\n", + "Set up a simulation and analyze it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38137e05", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(name=\"Setup1\", setup_type=\"HFSSDriven\", Frequency=\"10GHz\")\n", + "\n", + "setup.create_frequency_sweep(\n", + " unit=\"GHz\",\n", + " name=\"Sweep1\",\n", + " start_frequency=8,\n", + " stop_frequency=12,\n", + " sweep_type=\"Interpolating\",\n", + ")\n", + "\n", + "hfss.save_project()\n", + "hfss.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "9bc3974e", + "metadata": {}, + "source": [ + "## Plot S11\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ba6fb0d", + "metadata": {}, + "outputs": [], + "source": [ + "plot_data = hfss.get_traces_for_plot()\n", + "report = hfss.post.create_report(plot_data)\n", + "solution = report.get_solution_data()\n", + "plt = solution.plot(solution.expressions)" + ] + }, + { + "cell_type": "markdown", + "id": "26dfa0a4", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ccfc7dc", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "82ccab65", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41c4a545", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/armoured_cable.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/armoured_cable.ipynb.txt new file mode 100644 index 00000000..6dd53ba7 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/armoured_cable.ipynb.txt @@ -0,0 +1,723 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "195b75e8", + "metadata": {}, + "source": [ + "# Cable parameter identification" + ] + }, + { + "cell_type": "markdown", + "id": "99b103bf", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to perform these tasks:\n", + "\n", + " - Create a Q2D design using modeler primitives and an imported CAD.\n", + " - Set up the simulation.\n", + " - Link the solution to a Simplorer design.\n", + "\n", + "For information on the cable model used in this example, see\n", + "[4 Core Armoured Power Cable](https://www.luxingcable.com/low-voltage-cables/4-core-armoured-power-cable.html).\n", + "\n", + "Keywords: **Q2D**, **EMC**, **cable**." + ] + }, + { + "cell_type": "markdown", + "id": "b5d0ec69", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f52745c", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8209a63d", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "6e593df9", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d3e14ef", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "4571270a", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23850a1c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "1961af50", + "metadata": {}, + "source": [ + "## Set up for model creation\n", + "\n", + "Initialize cable sizing by specifying radii in millimeters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7547aa1", + "metadata": {}, + "outputs": [], + "source": [ + "c_strand_radius = 2.575\n", + "cable_n_cores = 4\n", + "core_n_strands = 6\n", + "core_xlpe_ins_thickness = 0.5\n", + "core_xy_coord = math.ceil(3 * c_strand_radius + 2 * core_xlpe_ins_thickness)" + ] + }, + { + "cell_type": "markdown", + "id": "38b5910b", + "metadata": {}, + "source": [ + "Initialize radii of further structures incrementally adding thicknesses." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bb68aaa", + "metadata": {}, + "outputs": [], + "source": [ + "filling_radius = 1.4142 * (\n", + " core_xy_coord + 3 * c_strand_radius + core_xlpe_ins_thickness + 0.5\n", + ")\n", + "inner_sheath_radius = filling_radius + 0.75\n", + "armour_thickness = 3\n", + "armour_radius = inner_sheath_radius + armour_thickness\n", + "outer_sheath_radius = armour_radius + 2" + ] + }, + { + "cell_type": "markdown", + "id": "df7f15f2", + "metadata": {}, + "source": [ + "Initialize radii." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c56fae0a", + "metadata": {}, + "outputs": [], + "source": [ + "armour_centre_pos = inner_sheath_radius + armour_thickness / 2.0\n", + "arm_strand_rad = armour_thickness / 2.0 - 0.2\n", + "n_arm_strands = 30" + ] + }, + { + "cell_type": "markdown", + "id": "7fa77619", + "metadata": {}, + "source": [ + "Start an instance of Q2D Extractor, providing the version, project name, design\n", + "name, and type." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "307d7868", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"Q2D_ArmouredCableExample.aedt\")\n", + "q2d_design_name = \"2D_Extractor_Cable\"\n", + "setup_name = \"AnalysisSeetup\"\n", + "sweep_name = \"FreqSweep\"\n", + "tb_design_name = \"CableSystem\"\n", + "q2d = ansys.aedt.core.Q2d(\n", + " project=project_name,\n", + " design=q2d_design_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + ")\n", + "q2d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "0dc71e17", + "metadata": {}, + "source": [ + "Assign variables to the Q3D design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02fdd994", + "metadata": {}, + "outputs": [], + "source": [ + "core_params = {\n", + " \"n_cores\": str(cable_n_cores),\n", + " \"n_strands_core\": str(core_n_strands),\n", + " \"c_strand_radius\": str(c_strand_radius) + \"mm\",\n", + " \"c_strand_xy_coord\": str(core_xy_coord) + \"mm\",\n", + "}\n", + "outer_params = {\n", + " \"filling_radius\": str(filling_radius) + \"mm\",\n", + " \"inner_sheath_radius\": str(inner_sheath_radius) + \"mm\",\n", + " \"armour_radius\": str(armour_radius) + \"mm\",\n", + " \"outer_sheath_radius\": str(outer_sheath_radius) + \"mm\",\n", + "}\n", + "armour_params = {\n", + " \"armour_centre_pos\": str(armour_centre_pos) + \"mm\",\n", + " \"arm_strand_rad\": str(arm_strand_rad) + \"mm\",\n", + " \"n_arm_strands\": str(n_arm_strands),\n", + "}\n", + "for k, v in core_params.items():\n", + " q2d[k] = v\n", + "for k, v in outer_params.items():\n", + " q2d[k] = v\n", + "for k, v in armour_params.items():\n", + " q2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "4c9b3665", + "metadata": {}, + "source": [ + "Cable insulators require the definition of specific materials since they are not\n", + "included in the ``Sys`` library.\n", + "\n", + "Define Plastic, PE (cross-linked, wire, and cable grade):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73609a6d", + "metadata": {}, + "outputs": [], + "source": [ + "mat_pe_cable_grade = q2d.materials.add_material(\"plastic_pe_cable_grade\")\n", + "mat_pe_cable_grade.conductivity = \"1.40573e-16\"\n", + "mat_pe_cable_grade.permittivity = \"2.09762\"\n", + "mat_pe_cable_grade.dielectric_loss_tangent = \"0.000264575\"\n", + "mat_pe_cable_grade.update()" + ] + }, + { + "cell_type": "markdown", + "id": "f6d36723", + "metadata": {}, + "source": [ + "Define Plastic, PP (10% carbon fiber):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa63d113", + "metadata": {}, + "outputs": [], + "source": [ + "mat_pp = q2d.materials.add_material(\"plastic_pp_carbon_fiber\")\n", + "mat_pp.conductivity = \"0.0003161\"\n", + "mat_pp.update()" + ] + }, + { + "cell_type": "markdown", + "id": "c98214dc", + "metadata": {}, + "source": [ + "## Create model\n", + "\n", + "Create the geometry for core strands, fill, and XLPE insulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69b5f01f", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.create_coordinate_system(\n", + " origin=[\"c_strand_xy_coord\", \"c_strand_xy_coord\", \"0mm\"], name=\"CS_c_strand_1\"\n", + ")\n", + "q2d.modeler.set_working_coordinate_system(\"CS_c_strand_1\")\n", + "c1_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"c_strand_radius\",\n", + " name=\"c_strand_1\",\n", + " material=\"copper\",\n", + ")\n", + "c2_id = c1_id.duplicate_along_line(\n", + " vector=[\"0mm\", \"2.0*c_strand_radius\", \"0mm\"], clones=2\n", + ")\n", + "q2d.modeler.duplicate_around_axis(c2_id, axis=\"Z\", angle=360 / core_n_strands, clones=6)\n", + "c_unite_name = q2d.modeler.unite(q2d.get_all_conductors_names())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e81c2244", + "metadata": {}, + "outputs": [], + "source": [ + "fill_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"3*c_strand_radius\",\n", + " name=\"c_strand_fill\",\n", + " material=\"plastic_pp_carbon_fiber\",\n", + ")\n", + "fill_id.color = (255, 255, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f28fc81d", + "metadata": {}, + "outputs": [], + "source": [ + "xlpe_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"3*c_strand_radius+\" + str(core_xlpe_ins_thickness) + \"mm\",\n", + " name=\"c_strand_xlpe\",\n", + " material=\"plastic_pe_cable_grade\",\n", + ")\n", + "xlpe_id.color = (0, 128, 128)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8565db1", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.set_working_coordinate_system(\"Global\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "957ac8b9", + "metadata": {}, + "outputs": [], + "source": [ + "all_obj_names = q2d.get_all_conductors_names() + q2d.get_all_dielectrics_names()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d513694", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.duplicate_around_axis(\n", + " all_obj_names, axis=\"Z\", angle=360 / cable_n_cores, clones=4\n", + ")\n", + "cond_names = q2d.get_all_conductors_names()" + ] + }, + { + "cell_type": "markdown", + "id": "1b507fb9", + "metadata": {}, + "source": [ + "Define the filling object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1636452", + "metadata": {}, + "outputs": [], + "source": [ + "filling_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"filling_radius\",\n", + " name=\"Filling\",\n", + " material=\"plastic_pp_carbon_fiber\",\n", + ")\n", + "filling_id.color = (255, 255, 180)" + ] + }, + { + "cell_type": "markdown", + "id": "0fdd160b", + "metadata": {}, + "source": [ + "Define the inner sheath." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a94f08b7", + "metadata": {}, + "outputs": [], + "source": [ + "inner_sheath_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"inner_sheath_radius\",\n", + " name=\"InnerSheath\",\n", + " material=\"PVC plastic\",\n", + ")\n", + "inner_sheath_id.color = (0, 0, 0)" + ] + }, + { + "cell_type": "markdown", + "id": "cf96f475", + "metadata": {}, + "source": [ + "Create the armature fill." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e00bdf9d", + "metadata": {}, + "outputs": [], + "source": [ + "arm_fill_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"armour_radius\",\n", + " name=\"ArmourFilling\",\n", + " material=\"plastic_pp_carbon_fiber\",\n", + ")\n", + "arm_fill_id.color = (255, 255, 255)" + ] + }, + { + "cell_type": "markdown", + "id": "2dbf4e2e", + "metadata": {}, + "source": [ + "Create the geometry for the outer sheath." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e59d3b21", + "metadata": {}, + "outputs": [], + "source": [ + "outer_sheath_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"0mm\", \"0mm\"],\n", + " radius=\"outer_sheath_radius\",\n", + " name=\"OuterSheath\",\n", + " material=\"PVC plastic\",\n", + ")\n", + "outer_sheath_id.color = (0, 0, 0)" + ] + }, + { + "cell_type": "markdown", + "id": "6e3732fa", + "metadata": {}, + "source": [ + "Create the geometry for the armature steel strands." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce9b83e4", + "metadata": {}, + "outputs": [], + "source": [ + "arm_strand_1_id = q2d.modeler.create_circle(\n", + " origin=[\"0mm\", \"armour_centre_pos\", \"0mm\"],\n", + " radius=\"1.1mm\",\n", + " name=\"arm_strand_1\",\n", + " material=\"steel_stainless\",\n", + ")\n", + "arm_strand_1_id.color = (128, 128, 64)\n", + "arm_strand_1_id.duplicate_around_axis(\n", + " axis=\"Z\", angle=\"360deg/n_arm_strands\", clones=\"n_arm_strands\"\n", + ")\n", + "arm_strand_names = q2d.modeler.get_objects_w_string(\"arm_strand\")" + ] + }, + { + "cell_type": "markdown", + "id": "962395b4", + "metadata": {}, + "source": [ + "Define the outer region that defines the solution domain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7956da4", + "metadata": {}, + "outputs": [], + "source": [ + "region = q2d.modeler.create_region([500, 500, 500, 500])\n", + "region.material_name = \"vacuum\"" + ] + }, + { + "cell_type": "markdown", + "id": "11514427", + "metadata": {}, + "source": [ + "Assign conductors and reference ground." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6091652", + "metadata": {}, + "outputs": [], + "source": [ + "obj = [q2d.modeler.get_object_from_name(i) for i in cond_names]\n", + "[\n", + " q2d.assign_single_conductor(\n", + " name=\"C1\" + str(obj.index(i) + 1), assignment=i, conductor_type=\"SignalLine\"\n", + " )\n", + " for i in obj\n", + "]\n", + "obj = [q2d.modeler.get_object_from_name(i) for i in arm_strand_names]\n", + "q2d.assign_single_conductor(\n", + " name=\"gnd\", assignment=obj, conductor_type=\"ReferenceGround\"\n", + ")\n", + "q2d.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "ece971a5", + "metadata": {}, + "source": [ + "Specify the design settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "801bf840", + "metadata": {}, + "outputs": [], + "source": [ + "lumped_length = \"100m\"\n", + "q2d.design_settings[\"LumpedLength\"] = lumped_length" + ] + }, + { + "cell_type": "markdown", + "id": "3505af6e", + "metadata": {}, + "source": [ + "## Solve model\n", + "\n", + "Insert the setup and frequency sweep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "611c7149", + "metadata": {}, + "outputs": [], + "source": [ + "q2d_setup = q2d.create_setup(name=setup_name)\n", + "q2d_sweep = q2d_setup.add_sweep(name=sweep_name)" + ] + }, + { + "cell_type": "markdown", + "id": "c80e1ab7", + "metadata": {}, + "source": [ + "The cable model is generated by running two solution types:\n", + "\n", + "1. Capacitance and conductance per unit length (CG).\n", + "For this model, the CG solution runs in a few seconds.\n", + "\n", + "2. Series resistance and inductance (RL).\n", + "For this model, the solution time can range from 15-20 minutes,\n", + "depending on the available hardware.\n", + "\n", + "Uncomment the following line to run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53c8a9c7", + "metadata": {}, + "outputs": [], + "source": [ + "# q2d.analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "12901e79", + "metadata": {}, + "source": [ + "## Evaluate results\n", + "\n", + "Add a Simplorer/Twin Builder design and the Q3D dynamic component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b71296b2", + "metadata": {}, + "outputs": [], + "source": [ + "tb = ansys.aedt.core.TwinBuilder(design=tb_design_name, version=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "2168f809", + "metadata": {}, + "source": [ + "Add a Q2D dynamic component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cf7b0d2", + "metadata": {}, + "outputs": [], + "source": [ + "tb.add_q3d_dynamic_component(\n", + " project_name,\n", + " q2d_design_name,\n", + " q2d_setup.name,\n", + " q2d_sweep.name,\n", + " model_depth=lumped_length,\n", + " coupling_matrix_name=\"Original\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a2666bf6", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17f56814", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "d4a20e0d", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47a3aa37", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/busbar.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/busbar.ipynb.txt new file mode 100644 index 00000000..159c27ab --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/busbar.ipynb.txt @@ -0,0 +1,400 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "036e0d5d", + "metadata": {}, + "source": [ + "# Busbar analysis" + ] + }, + { + "cell_type": "markdown", + "id": "58395530", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a busbar design in\n", + "Q3D Extractor and run a simulation.\n", + "\n", + "Keywords: **Q3D**, **EMC*, **busbar**." + ] + }, + { + "cell_type": "markdown", + "id": "3346d93e", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "058db78e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "902e0ada", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "21d9846b", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d960607", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False" + ] + }, + { + "cell_type": "markdown", + "id": "b9c47ee8", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9fedda77", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "fa791b81", + "metadata": {}, + "source": [ + "## Launch AEDT and Q3D Extractor\n", + "\n", + "Launch AEDT 2024 R2 in graphical mode and launch Q3D Extractor. This example uses SI units." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a408bb7", + "metadata": {}, + "outputs": [], + "source": [ + "q3d = ansys.aedt.core.Q3d(\n", + " project=os.path.join(temp_folder.name, \"busbar.aedt\"),\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b761fa87", + "metadata": {}, + "source": [ + "## Create and set up the Q3D model\n", + "\n", + "Create polylines for three busbars and a box for the substrate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c94dd10", + "metadata": {}, + "outputs": [], + "source": [ + "b1 = q3d.modeler.create_polyline(\n", + " points=[[0, 0, 0], [-100, 0, 0]],\n", + " name=\"Bar1\",\n", + " material=\"copper\",\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=\"5mm\",\n", + " xsection_height=\"1mm\",\n", + ")\n", + "q3d.modeler[\"Bar1\"].color = (255, 0, 0)\n", + "\n", + "q3d.modeler.create_polyline(\n", + " points=[[0, -15, 0], [-150, -15, 0]],\n", + " name=\"Bar2\",\n", + " material=\"aluminum\",\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=\"5mm\",\n", + " xsection_height=\"1mm\",\n", + ")\n", + "q3d.modeler[\"Bar2\"].color = (0, 255, 0)\n", + "\n", + "q3d.modeler.create_polyline(\n", + " points=[[0, -30, 0], [-175, -30, 0], [-175, -10, 0]],\n", + " name=\"Bar3\",\n", + " material=\"copper\",\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=\"5mm\",\n", + " xsection_height=\"1mm\",\n", + ")\n", + "q3d.modeler[\"Bar3\"].color = (0, 0, 255)\n", + "\n", + "q3d.modeler.create_box(\n", + " origin=[50, 30, -0.5],\n", + " sizes=[-250, -100, -3],\n", + " name=\"substrate\",\n", + " material=\"FR4_epoxy\",\n", + ")\n", + "q3d.modeler[\"substrate\"].color = (128, 128, 128)\n", + "q3d.modeler[\"substrate\"].transparency = 0.8\n", + "\n", + "q3d.plot(\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"Q3D.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bff3855f", + "metadata": {}, + "source": [ + "Identify nets and assign sources and sinks to all nets.\n", + "There is a source and sink for each busbar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0071a3f7", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.auto_identify_nets()\n", + "\n", + "q3d.source(assignment=\"Bar1\", direction=q3d.AxisDir.XPos, name=\"Source1\")\n", + "q3d.sink(assignment=\"Bar1\", direction=q3d.AxisDir.XNeg, name=\"Sink1\")\n", + "\n", + "q3d.source(assignment=\"Bar2\", direction=q3d.AxisDir.XPos, name=\"Source2\")\n", + "q3d.sink(assignment=\"Bar2\", direction=q3d.AxisDir.XNeg, name=\"Sink2\")\n", + "q3d.source(assignment=\"Bar3\", direction=q3d.AxisDir.XPos, name=\"Source3\")\n", + "bar3_sink = q3d.sink(assignment=\"Bar3\", direction=q3d.AxisDir.YPos, name=\"Sink3\")" + ] + }, + { + "cell_type": "markdown", + "id": "654ca8bd", + "metadata": {}, + "source": [ + "Print information about nets and terminal assignments." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10c5cade", + "metadata": {}, + "outputs": [], + "source": [ + "print(q3d.nets)\n", + "print(q3d.net_sinks(\"Bar1\"))\n", + "print(q3d.net_sinks(\"Bar2\"))\n", + "print(q3d.net_sinks(\"Bar3\"))\n", + "print(q3d.net_sources(\"Bar1\"))\n", + "print(q3d.net_sources(\"Bar2\"))\n", + "print(q3d.net_sources(\"Bar3\"))" + ] + }, + { + "cell_type": "markdown", + "id": "5fff0891", + "metadata": {}, + "source": [ + "Create the solution setup and define the frequency range for the solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "294a9f75", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = q3d.create_setup(props={\"AdaptiveFreq\": \"100MHz\"})\n", + "sweep = setup1.add_sweep()\n", + "sweep.props[\"RangeStart\"] = \"1MHz\"\n", + "sweep.props[\"RangeEnd\"] = \"100MHz\"\n", + "sweep.props[\"RangeStep\"] = \"5MHz\"\n", + "sweep.update()" + ] + }, + { + "cell_type": "markdown", + "id": "f2d634ee", + "metadata": {}, + "source": [ + "### Set up for postprocessing\n", + "\n", + "Specify the traces to display after solving the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8085691c", + "metadata": {}, + "outputs": [], + "source": [ + "data_plot_self = q3d.matrices[0].get_sources_for_plot(\n", + " get_self_terms=True, get_mutual_terms=False\n", + ")\n", + "data_plot_mutual = q3d.get_traces_for_plot(\n", + " get_self_terms=False, get_mutual_terms=True, category=\"C\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5ad4ffeb", + "metadata": {}, + "source": [ + "Define a plot and a data table in AEDT for visualizing results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "124756bc", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.post.create_report(expressions=data_plot_self)\n", + "q3d.post.create_report(\n", + " expressions=data_plot_mutual, context=\"Original\", plot_type=\"Data Table\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "21527f51", + "metadata": {}, + "source": [ + "## Analyze\n", + "\n", + "Solve the setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6dbdd7c", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.analyze(cores=NUM_CORES)\n", + "q3d.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "8a34f943", + "metadata": {}, + "source": [ + "Retrieve solution data for processing in Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ee38d5c", + "metadata": {}, + "outputs": [], + "source": [ + "data = q3d.post.get_solution_data(expressions=data_plot_self, context=\"Original\")\n", + "data.data_magnitude()\n", + "data.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "e66b7414", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06391ddc", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.save_project()\n", + "q3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1d749ead", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "134111ef", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/choke.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/choke.ipynb.txt new file mode 100644 index 00000000..187ad814 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/choke.ipynb.txt @@ -0,0 +1,516 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dace28f7", + "metadata": {}, + "source": [ + "# Choke\n", + "\n", + "This example shows how to use PyAEDT to create a choke setup in HFSS.\n", + "\n", + "Keywords: **HFSS**, **EMC**, **choke**, ." + ] + }, + { + "cell_type": "markdown", + "id": "c51583f5", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130bad56", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1351ace", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "905d5f37", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5d1cde7", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "732ad369", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8b62ea8", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "e6d3f224", + "metadata": {}, + "source": [ + "## Launch HFSS" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e8496e0", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"choke.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " solution_type=\"Terminal\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f3c6f77f", + "metadata": {}, + "source": [ + "## Define parameters\n", + "\n", + "The dictionary values contain the different parameter values of the core and\n", + "the windings that compose the choke. You must not change the main structure of\n", + "the dictionary. The dictionary has many primary keys, including\n", + "``\"Number of Windings\"``, ``\"Layer\"``, and ``\"Layer Type\"``, that have\n", + "dictionaries as values. The keys of these dictionaries are secondary keys\n", + "of the dictionary values, such as ``\"1\"``, ``\"2\"``, ``\"3\"``, ``\"4\"``, and\n", + "``\"Simple\"``.\n", + "\n", + "You must not modify the primary or secondary keys. You can modify only their values.\n", + "You must not change the data types for these keys. For the dictionaries from\n", + "``\"Number of Windings\"`` through ``\"Wire Section\"``, values must be Boolean. Only\n", + "one value per dictionary can be ``True``. If all values are ``True``, only the first one\n", + "remains set to ``True``. If all values are ``False``, the first value is chosen as the\n", + "correct one by default. For the dictionaries from ``\"Core\"`` through ``\"Inner Winding\"``,\n", + "values must be strings, floats, or integers.\n", + "\n", + "Descriptions follow for the primary keys:\n", + "\n", + "- ``\"Number of Windings\"``: Number of windings around the core.\n", + "- ``\"Layer\"``: Number of layers of all windings.\n", + "- ``\"Layer Type\"``: Whether layers of a winding are linked to each other\n", + "- ``\"Similar Layer\"``: Whether layers of a winding have the same number of turns and\n", + "same spacing between turns.\n", + "- ``\"Mode\"``: When there are only two windows, whether they are in common or differential mode.\n", + "- ``\"Wire Section\"``: Type of wire section and number of segments.\n", + "- ``\"Core\"``: Design of the core.\n", + "- ``\"Outer Winding\"``: Design of the first layer or outer layer of a winding and the common\n", + "parameters for all layers.\n", + "- ``\"Mid Winding\"``: Turns and turns spacing (``Coil Pit``) for the second or\n", + "mid layer if it is necessary.\n", + "- ``\"Inner Winding\"``: Turns and turns spacing (``Coil Pit``) for the third or inner\n", + "layer if it is necessary.\n", + "- ``\"Occupation(%)\"``: An informative parameter that is useless to modify.\n", + "\n", + "The following parameter values work. You can modify them if you want." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c2719f9", + "metadata": {}, + "outputs": [], + "source": [ + "values = {\n", + " \"Number of Windings\": {\"1\": False, \"2\": True, \"3\": False, \"4\": False},\n", + " \"Layer\": {\"Simple\": False, \"Double\": True, \"Triple\": False},\n", + " \"Layer Type\": {\"Separate\": False, \"Linked\": True},\n", + " \"Similar Layer\": {\"Similar\": False, \"Different\": True},\n", + " \"Mode\": {\"Differential\": False, \"Common\": True},\n", + " \"Wire Section\": {\"None\": False, \"Hexagon\": True, \"Octagon\": False, \"Circle\": False},\n", + " \"Core\": {\n", + " \"Name\": \"Core\",\n", + " \"Material\": \"ferrite\",\n", + " \"Inner Radius\": 20,\n", + " \"Outer Radius\": 30,\n", + " \"Height\": 10,\n", + " \"Chamfer\": 0.8,\n", + " },\n", + " \"Outer Winding\": {\n", + " \"Name\": \"Winding\",\n", + " \"Material\": \"copper\",\n", + " \"Inner Radius\": 20,\n", + " \"Outer Radius\": 30,\n", + " \"Height\": 10,\n", + " \"Wire Diameter\": 1.5,\n", + " \"Turns\": 20,\n", + " \"Coil Pit(deg)\": 0.1,\n", + " \"Occupation(%)\": 0,\n", + " },\n", + " \"Mid Winding\": {\"Turns\": 25, \"Coil Pit(deg)\": 0.1, \"Occupation(%)\": 0},\n", + " \"Inner Winding\": {\"Turns\": 4, \"Coil Pit(deg)\": 0.1, \"Occupation(%)\": 0},\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "43d9af71", + "metadata": {}, + "source": [ + "## Convert dictionary to JSON file\n", + "\n", + "Convert the dictionary to a JSON file. You must supply the path of the\n", + "JSON file as an argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fe11022", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = os.path.join(hfss.working_directory, \"choke_example.json\")\n", + "with open(json_path, \"w\") as outfile:\n", + " json.dump(values, outfile)" + ] + }, + { + "cell_type": "markdown", + "id": "8bab89f6", + "metadata": {}, + "source": [ + "## Verify parameters of JSON file\n", + "\n", + "Verify parameters of the JSON file. The ``check_choke_values()`` method takes\n", + "the JSON file path as an argument and does the following:\n", + "\n", + "- Checks if the JSON file is correctly written (as explained earlier).\n", + "- Checks equations on windings parameters to avoid having unintended intersections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faea8468", + "metadata": {}, + "outputs": [], + "source": [ + "dictionary_values = hfss.modeler.check_choke_values(\n", + " json_path, create_another_file=False\n", + ")\n", + "print(dictionary_values)" + ] + }, + { + "cell_type": "markdown", + "id": "48b5a25c", + "metadata": {}, + "source": [ + "## Create choke\n", + "\n", + "Create the choke. The ``Hfss.modeler.create_choke()`` method takes the JSON file path as an\n", + "argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cd95405", + "metadata": {}, + "outputs": [], + "source": [ + "list_object = hfss.modeler.create_choke(json_path)\n", + "print(list_object)\n", + "core = list_object[1]\n", + "first_winding_list = list_object[2]\n", + "second_winding_list = list_object[3]" + ] + }, + { + "cell_type": "markdown", + "id": "81ce7d20", + "metadata": {}, + "source": [ + "## Create ground" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6db3df61", + "metadata": {}, + "outputs": [], + "source": [ + "ground_radius = 1.2 * dictionary_values[1][\"Outer Winding\"][\"Outer Radius\"]\n", + "ground_position = [0, 0, first_winding_list[1][0][2] - 2]\n", + "ground = hfss.modeler.create_circle(\n", + " \"XY\", ground_position, ground_radius, name=\"GND\", material=\"copper\"\n", + ")\n", + "coat = hfss.assign_coating(ground, is_infinite_ground=True)\n", + "ground.transparency = 0.9" + ] + }, + { + "cell_type": "markdown", + "id": "d020b91f", + "metadata": {}, + "source": [ + "## Create lumped ports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c621c085", + "metadata": {}, + "outputs": [], + "source": [ + "port_position_list = [\n", + " [\n", + " first_winding_list[1][0][0],\n", + " first_winding_list[1][0][1],\n", + " first_winding_list[1][0][2] - 1,\n", + " ],\n", + " [\n", + " first_winding_list[1][-1][0],\n", + " first_winding_list[1][-1][1],\n", + " first_winding_list[1][-1][2] - 1,\n", + " ],\n", + " [\n", + " second_winding_list[1][0][0],\n", + " second_winding_list[1][0][1],\n", + " second_winding_list[1][0][2] - 1,\n", + " ],\n", + " [\n", + " second_winding_list[1][-1][0],\n", + " second_winding_list[1][-1][1],\n", + " second_winding_list[1][-1][2] - 1,\n", + " ],\n", + "]\n", + "port_dimension_list = [2, dictionary_values[1][\"Outer Winding\"][\"Wire Diameter\"]]\n", + "for position in port_position_list:\n", + " sheet = hfss.modeler.create_rectangle(\n", + " \"XZ\", position, port_dimension_list, name=\"sheet_port\"\n", + " )\n", + " sheet.move([-dictionary_values[1][\"Outer Winding\"][\"Wire Diameter\"] / 2, 0, -1])\n", + " hfss.lumped_port(\n", + " assignment=sheet.name,\n", + " name=\"port_\" + str(port_position_list.index(position) + 1),\n", + " reference=[ground],\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "dfeb4018", + "metadata": {}, + "source": [ + "## Create mesh" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "078b0705", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "cylinder_height = 2.5 * dictionary_values[1][\"Outer Winding\"][\"Height\"]\n", + "cylinder_position = [0, 0, first_winding_list[1][0][2] - 4]\n", + "mesh_operation_cylinder = hfss.modeler.create_cylinder(\n", + " \"XY\",\n", + " cylinder_position,\n", + " ground_radius,\n", + " cylinder_height,\n", + " num_sides=36,\n", + " name=\"mesh_cylinder\",\n", + ")\n", + "\n", + "hfss.mesh.assign_length_mesh(\n", + " [mesh_operation_cylinder],\n", + " maximum_length=15,\n", + " maximum_elements=None,\n", + " name=\"choke_mesh\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4b95354a", + "metadata": {}, + "source": [ + "## Create boundaries\n", + "\n", + "Create the boundaries. A region with openings is needed to run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0cce5f2", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "region = hfss.modeler.create_region(pad_percent=1000)" + ] + }, + { + "cell_type": "markdown", + "id": "d25b7c59", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup with a sweep to run the simulation. Depending on your machine's\n", + "computing power, the simulation can take some time to run." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2ed0856", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(\"MySetup\")\n", + "setup.props[\"Frequency\"] = \"50MHz\"\n", + "setup[\"MaximumPasses\"] = 10\n", + "hfss.create_linear_count_sweep(\n", + " setup=setup.name,\n", + " units=\"MHz\",\n", + " start_frequency=0.1,\n", + " stop_frequency=100,\n", + " num_of_freq_points=100,\n", + " name=\"sweep1\",\n", + " sweep_type=\"Interpolating\",\n", + " save_fields=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b4252cdc", + "metadata": {}, + "source": [ + "## Plot objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4cdb350", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "hfss.modeler.fit_all()\n", + "hfss.plot(\n", + " show=False,\n", + " output_file=os.path.join(hfss.working_directory, \"Image.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d95e45b4", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e81bdd9", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e5185a4c", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f7bf174", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/eigenmode.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/eigenmode.ipynb.txt new file mode 100644 index 00000000..5463efb2 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/eigenmode.ipynb.txt @@ -0,0 +1,384 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "910240b2", + "metadata": {}, + "source": [ + "# Eigenmode filter\n", + "\n", + "This example shows how to use PyAEDT to automate the Eigenmode solver in HFSS.\n", + "Eigenmode analysis can be applied to open radiating structures\n", + "using an absorbing boundary condition. This type of analysis is useful for\n", + "determining the resonant frequency of a geometry or an antenna, and it can be used to refine\n", + "the mesh at the resonance, even when the resonant frequency of the antenna is not known.\n", + "\n", + "The challenge posed by this method is to identify and filter the non-physical modes\n", + "resulting from reflection from boundaries of the main domain.\n", + "Because the Eigenmode solver sorts by frequency and does not filter on the\n", + "quality factor, these virtual modes are present when the Eigenmode approach is\n", + "applied to nominally open structures.\n", + "\n", + "When looking for resonant modes over a wide frequency range for nominally\n", + "enclosed structures, several iterations may be required because the minimum frequency\n", + "is determined manually. Simulations re-run until the complete frequency range is covered\n", + "and all important physical modes are calculated.\n", + "\n", + "The following script finds the physical modes of a model in a wide frequency\n", + "range by automating the solution setup.\n", + "During each simulation, a user-defined number of modes is simulated, and the modes\n", + "with a Q higher than a user-defined value are filtered.\n", + "The next simulation automatically continues to find modes having a frequency higher\n", + "than the last mode of the previous analysis.\n", + "This continues until the maximum frequency in the desired range is achieved.\n", + "\n", + "Keywords: **HFSS**, **Eigenmode**, **resonance**." + ] + }, + { + "cell_type": "markdown", + "id": "dbbaf2ac", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "556630e8", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a36dbd12", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "288d093d", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45e1a88b", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "fd2c73a1", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80fadaad", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "0f83d263", + "metadata": {}, + "source": [ + "## Download 3D component\n", + "Download the 3D component that is needed to run the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "879a20f5", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " \"eigenmode\", \"emi_PCB_house.aedt\", temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7324b368", + "metadata": {}, + "source": [ + "## Launch AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c88ab91", + "metadata": {}, + "outputs": [], + "source": [ + "d = ansys.aedt.core.launch_desktop(\n", + " AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "79710a8f", + "metadata": {}, + "source": [ + "## Launch HFSS\n", + "\n", + "Create an HFSS design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1dacaf77", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = ansys.aedt.core.Hfss(\n", + " version=AEDT_VERSION, project=project_path, non_graphical=NG_MODE\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3ce36712", + "metadata": {}, + "source": [ + "## Input parameters for Eigenmode solver\n", + "\n", + "The geometry and material should be already set. The analyses are generated by the code.\n", + "The ``num_modes`` parameter is the number of modes during each analysis. The maximum\n", + "allowed number is 20. Entering a number higher than 10 might result in a long simulation\n", + "time as the Eigenmode solver must converge on modes. The ``fmin`` parameter is the lowest\n", + "frequency of interest. The ``fmax`` parameter is the highest frequency of interest.\n", + "The ``limit`` parameter determines which modes are ignored." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a2dcf19", + "metadata": {}, + "outputs": [], + "source": [ + "num_modes = 6\n", + "fmin = 1\n", + "fmax = 2\n", + "next_fmin = fmin\n", + "setup_nr = 1\n", + "limit = 10\n", + "resonance = {}" + ] + }, + { + "cell_type": "markdown", + "id": "6942316e", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Find modes\n", + "\n", + "The following cell defines a function that can be used to create and solve an Eigenmode setup.\n", + "After solving the model, information about each mode is saved for subsequent processing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35bf5dd5", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "def find_resonance():\n", + " # Setup creation\n", + " next_min_freq = f\"{next_fmin} GHz\"\n", + " setup_name = f\"em_setup{setup_nr}\"\n", + " setup = hfss.create_setup(setup_name)\n", + " setup.props[\"MinimumFrequency\"] = next_min_freq\n", + " setup.props[\"NumModes\"] = num_modes\n", + " setup.props[\"ConvergeOnRealFreq\"] = True\n", + " setup.props[\"MaximumPasses\"] = 10\n", + " setup.props[\"MinimumPasses\"] = 3\n", + " setup.props[\"MaxDeltaFreq\"] = 5\n", + "\n", + " # Analyze the Eigenmode setup\n", + " hfss.analyze_setup(setup_name, cores=NUM_CORES, use_auto_settings=True)\n", + "\n", + " # Get the Q and real frequency of each mode\n", + " eigen_q_quantities = hfss.post.available_report_quantities(\n", + " quantities_category=\"Eigen Q\"\n", + " )\n", + " eigen_mode_quantities = hfss.post.available_report_quantities()\n", + " data = {}\n", + " for i, expression in enumerate(eigen_mode_quantities):\n", + " eigen_q_value = hfss.post.get_solution_data(\n", + " expressions=eigen_q_quantities[i],\n", + " setup_sweep_name=f\"{setup_name} : LastAdaptive\",\n", + " report_category=\"Eigenmode\",\n", + " )\n", + " eigen_mode_value = hfss.post.get_solution_data(\n", + " expressions=expression,\n", + " setup_sweep_name=f\"{setup_name} : LastAdaptive\",\n", + " report_category=\"Eigenmode\",\n", + " )\n", + " data[i] = [eigen_q_value.data_real()[0], eigen_mode_value.data_real()[0]]\n", + "\n", + " print(data)\n", + " return data" + ] + }, + { + "cell_type": "markdown", + "id": "127ea5d9", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Automate Eigenmode solution\n", + "\n", + "Running the next cell calls the resonance function and saves\n", + "only those modes with a Q higher than the defined\n", + "limit. The ``find_resonance()`` function is called until the complete\n", + "frequency range is covered.\n", + "When the automation ends, the physical modes in the whole frequency\n", + "range are reported." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e624d4e", + "metadata": {}, + "outputs": [], + "source": [ + "while next_fmin < fmax:\n", + " output = find_resonance()\n", + " next_fmin = output[len(output) - 1][1] / 1e9\n", + " setup_nr += 1\n", + " cont_res = len(resonance)\n", + " for q in output:\n", + " if output[q][0] > limit:\n", + " resonance[cont_res] = output[q]\n", + " cont_res += 1\n", + "\n", + "resonance_frequencies = [f\"{resonance[i][1] / 1e9:.5} GHz\" for i in resonance]\n", + "print(str(resonance_frequencies))" + ] + }, + { + "cell_type": "markdown", + "id": "74db7d6e", + "metadata": {}, + "source": [ + "Plot the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c699b9b0", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.fit_all()\n", + "hfss.plot(\n", + " show=False,\n", + " output_file=os.path.join(hfss.working_directory, \"Image.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "523ddd94", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c622636e", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "5c9ba915", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed267185", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/flex_cable.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/flex_cable.ipynb.txt new file mode 100644 index 00000000..cf1c9ea4 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/flex_cable.ipynb.txt @@ -0,0 +1,520 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "95d04bf3", + "metadata": {}, + "source": [ + "# Flex cable CPWG\n", + "\n", + "This example shows how to use PyAEDT to create a flex cable CPWG\n", + "(coplanar waveguide with ground).\n", + "\n", + "Keywords: **HFSS**, **flex cable**, **CPWG**." + ] + }, + { + "cell_type": "markdown", + "id": "1ddc050f", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "922060ae", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "from math import cos, radians, sin, sqrt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0adab225", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.generic.general_methods import generate_unique_name" + ] + }, + { + "cell_type": "markdown", + "id": "27fd9c02", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8f7e5b1", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"" + ] + }, + { + "cell_type": "markdown", + "id": "45c47aa9", + "metadata": {}, + "source": [ + "## Set non-graphical mode\n", + "\n", + "Set non-graphical mode.\n", + "You can set ``non_graphical`` either to ``True`` or ``False``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd3140cc", + "metadata": {}, + "outputs": [], + "source": [ + "non_graphical = False" + ] + }, + { + "cell_type": "markdown", + "id": "eb48bad3", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c02c550", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "8cb8e014", + "metadata": {}, + "source": [ + "## Launch AEDT\n", + "\n", + "Launch AEDT, create an HFSS design, and save the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4887607c", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = ansys.aedt.core.Hfss(\n", + " version=AEDT_VERSION,\n", + " solution_type=\"DrivenTerminal\",\n", + " new_desktop=True,\n", + " non_graphical=non_graphical,\n", + ")\n", + "hfss.save_project(\n", + " os.path.join(temp_folder.name, generate_unique_name(\"example\") + \".aedt\")\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ff3adfb0", + "metadata": {}, + "source": [ + "## Modify design settings\n", + "\n", + "Modify some design settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69d73c8d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.change_material_override(True)\n", + "hfss.change_automatically_use_causal_materials(True)\n", + "hfss.create_open_region(\"100GHz\")\n", + "hfss.modeler.model_units = \"mil\"\n", + "hfss.mesh.assign_initial_mesh_from_slider(applycurvilinear=True)" + ] + }, + { + "cell_type": "markdown", + "id": "08272e6d", + "metadata": {}, + "source": [ + "## Create variables\n", + "\n", + "Create input variables for creating the flex cable CPWG." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ff4a930", + "metadata": {}, + "outputs": [], + "source": [ + "total_length = 300\n", + "theta = 120\n", + "r = 100\n", + "width = 3\n", + "height = 0.1\n", + "spacing = 1.53\n", + "gnd_width = 10\n", + "gnd_thickness = 2\n", + "\n", + "xt = (total_length - r * radians(theta)) / 2" + ] + }, + { + "cell_type": "markdown", + "id": "48bebf1d", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Create bend\n", + "\n", + "The ``create_bending()`` method creates a list of points for\n", + "the bend based on the curvature radius and extension." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10e1dbd4", + "metadata": {}, + "outputs": [], + "source": [ + "def create_bending(radius, extension=0):\n", + " points = [(-xt, 0, -radius), (0, 0, -radius)]\n", + "\n", + " for i in [radians(i) for i in range(theta)] + [radians(theta + 0.000000001)]:\n", + " points.append((radius * sin(i), 0, -radius * cos(i)))\n", + "\n", + " x1, y1, z1 = points[-1]\n", + " x0, y0, z0 = points[-2]\n", + "\n", + " scale = (xt + extension) / sqrt((x1 - x0) ** 2 + (z1 - z0) ** 2)\n", + " x, y, z = (x1 - x0) * scale + x0, 0, (z1 - z0) * scale + z0\n", + "\n", + " points[-1] = (x, y, z)\n", + " return points" + ] + }, + { + "cell_type": "markdown", + "id": "8d665dca", + "metadata": {}, + "source": [ + "## Draw signal line\n", + "\n", + "Draw a signal line to create a bent signal wire." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aefaab60", + "metadata": {}, + "outputs": [], + "source": [ + "points = create_bending(r, 1)\n", + "line = hfss.modeler.create_polyline(\n", + " points=points,\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=height,\n", + " xsection_height=width,\n", + " material=\"copper\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e0a7d86e", + "metadata": {}, + "source": [ + "## Draw ground line\n", + "\n", + "Draw a ground line to create two bent ground wires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3bbe6697", + "metadata": {}, + "outputs": [], + "source": [ + "gnd_r = [(x, spacing + width / 2 + gnd_width / 2, z) for x, y, z in points]\n", + "gnd_l = [(x, -y, z) for x, y, z in gnd_r]\n", + "\n", + "gnd_objs = []\n", + "for gnd in [gnd_r, gnd_l]:\n", + " x = hfss.modeler.create_polyline(\n", + " points=gnd,\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=height,\n", + " xsection_height=gnd_width,\n", + " material=\"copper\",\n", + " )\n", + " x.color = (255, 0, 0)\n", + " gnd_objs.append(x)" + ] + }, + { + "cell_type": "markdown", + "id": "ccc8b62e", + "metadata": {}, + "source": [ + "## Draw dielectric\n", + "\n", + "Draw a dielectric to create a dielectric cable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcbcbb0e", + "metadata": {}, + "outputs": [], + "source": [ + "points = create_bending(r + (height + gnd_thickness) / 2)\n", + "\n", + "fr4 = hfss.modeler.create_polyline(\n", + " points=points,\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=gnd_thickness,\n", + " xsection_height=width + 2 * spacing + 2 * gnd_width,\n", + " material=\"FR4_epoxy\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b350a2d6", + "metadata": {}, + "source": [ + "## Create bottom metals\n", + "\n", + "Create the bottom metals." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "245b3da9", + "metadata": {}, + "outputs": [], + "source": [ + "points = create_bending(r + height + gnd_thickness, 1)\n", + "\n", + "bot = hfss.modeler.create_polyline(\n", + " points=points,\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=height,\n", + " xsection_height=width + 2 * spacing + 2 * gnd_width,\n", + " material=\"copper\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "039ab517", + "metadata": {}, + "source": [ + "## Create port interfaces\n", + "\n", + "Create port interfaces (PEC enclosures)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "946a72a5", + "metadata": {}, + "outputs": [], + "source": [ + "port_faces = []\n", + "for face, blockname in zip([fr4.top_face_z, fr4.bottom_face_x], [\"b1\", \"b2\"]):\n", + " xc, yc, zc = face.center\n", + " positions = [i.position for i in face.vertices]\n", + "\n", + " port_sheet_list = [\n", + " ((x - xc) * 10 + xc, (y - yc) + yc, (z - zc) * 10 + zc) for x, y, z in positions\n", + " ]\n", + " s = hfss.modeler.create_polyline(\n", + " port_sheet_list, close_surface=True, cover_surface=True\n", + " )\n", + " center = [round(i, 6) for i in s.faces[0].center]\n", + "\n", + " port_block = hfss.modeler.thicken_sheet(s.name, -5)\n", + " port_block.name = blockname\n", + " for f in port_block.faces:\n", + "\n", + " if [round(i, 6) for i in f.center] == center:\n", + " port_faces.append(f)\n", + "\n", + " port_block.material_name = \"PEC\"\n", + "\n", + " for i in [line, bot] + gnd_objs:\n", + " i.subtract([port_block], True)\n", + "\n", + " print(port_faces)" + ] + }, + { + "cell_type": "markdown", + "id": "d1ad3e00", + "metadata": {}, + "source": [ + "## Create boundary condition\n", + "\n", + "Creates a Perfect E boundary condition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "269c7263", + "metadata": {}, + "outputs": [], + "source": [ + "boundary = []\n", + "for face in [fr4.top_face_y, fr4.bottom_face_y]:\n", + " s = hfss.modeler.create_object_from_face(face)\n", + " boundary.append(s)\n", + " hfss.assign_perfecte_to_sheets(s)" + ] + }, + { + "cell_type": "markdown", + "id": "a05156b9", + "metadata": {}, + "source": [ + "## Create ports\n", + "\n", + "Create ports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "808f4525", + "metadata": {}, + "outputs": [], + "source": [ + "for s, port_name in zip(port_faces, [\"1\", \"2\"]):\n", + " reference = [i.name for i in gnd_objs + boundary + [bot]] + [\"b1\", \"b2\"]\n", + "\n", + " hfss.wave_port(s.id, name=port_name, reference=reference)" + ] + }, + { + "cell_type": "markdown", + "id": "08bca3a4", + "metadata": {}, + "source": [ + "## Create setup and sweep\n", + "\n", + "Create the setup and sweep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee23f822", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(\"setup1\")\n", + "setup[\"Frequency\"] = \"2GHz\"\n", + "setup.props[\"MaximumPasses\"] = 10\n", + "setup.props[\"MinimumConvergedPasses\"] = 2\n", + "hfss.create_linear_count_sweep(\n", + " setup=\"setup1\",\n", + " units=\"GHz\",\n", + " start_frequency=1e-1,\n", + " stop_frequency=4,\n", + " num_of_freq_points=101,\n", + " name=\"sweep1\",\n", + " save_fields=False,\n", + " sweep_type=\"Interpolating\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3fa7a1d5", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26dd0ca4", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.release_desktop()" + ] + }, + { + "cell_type": "markdown", + "id": "76e16f3a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files.\n", + "The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18cd8302", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/emc/index.rst.txt b/version/dev/_sources/examples/high_frequency/emc/index.rst.txt new file mode 100644 index 00000000..1fa02e6b --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/index.rst.txt @@ -0,0 +1,124 @@ +EMC +~~~ + +These examples use PyAEDT to show some EMC applications. + +.. grid:: 2 + + .. grid-item-card:: Choke + :padding: 2 2 2 2 + :link: choke + :link-type: doc + + .. image:: _static/choke.png + :alt: Choke + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a choke setup in HFSS. + + .. grid-item-card:: Eigenmode filter + :padding: 2 2 2 2 + :link: eigenmode + :link-type: doc + + .. image:: _static/eigenmode.png + :alt: Eigenmode + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to automate the Eigenmode solver in HFSS. + + .. grid-item-card:: Flex cable CPWG + :padding: 2 2 2 2 + :link: flex_cable + :link-type: doc + + .. image:: _static/flex_cable.png + :alt: Flex cable + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a flex cable CPWG (coplanar waveguide with ground). + + .. grid-item-card:: Cable parameter identification + :padding: 2 2 2 2 + :link: armoured_cable + :link-type: doc + + .. image:: _static/armoured.png + :alt: Cable + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create see a 4 Core Armoured Power Cable. + + .. grid-item-card:: Busbar analysis + :padding: 2 2 2 2 + :link: busbar + :link-type: doc + + .. image:: _static/busbar.png + :alt: Busbar + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a busbar design in Q3D Extractor and run a simulation. + + .. grid-item-card:: Schematic subcircuit management + :padding: 2 2 2 2 + :link: subcircuit + :link-type: doc + + .. image:: _static/subcircuit.png + :alt: Cable + :width: 250px + :height: 200px + :align: center + + This example shows how to add a subcircuit to a circuit design. + It changes the focus within the hierarchy between the child subcircuit and the parent design. + + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: ../../aedt_general/modeler/circuit_schematic + :link-type: doc + + .. image:: ../../aedt_general/modeler/_static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: RF interference + :padding: 2 2 2 2 + :link: ../antenna/interferences/index + :link-type: doc + + .. image:: ../antenna/_static/emit_simple_cosite.png + :alt: EMIT logo + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some general capabilities of EMIT for RF interference. + + .. toctree:: + :hidden: + + choke + eigenmode + flex_cable + armoured_cable + busbar + subcircuit + ../../aedt_general/modeler/circuit_schematic + ../antenna/interferences/index diff --git a/version/dev/_sources/examples/high_frequency/emc/subcircuit.ipynb.txt b/version/dev/_sources/examples/high_frequency/emc/subcircuit.ipynb.txt new file mode 100644 index 00000000..7fb7d162 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/emc/subcircuit.ipynb.txt @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "44272f68", + "metadata": {}, + "source": [ + "# Schematic subcircuit management\n", + "\n", + "This example shows how to add a subcircuit to a circuit design.\n", + "It changes the focus within the hierarchy between\n", + "the child subcircuit and the parent design.\n", + "\n", + "Keywords: **Circuit**, **EMC**, **schematic**." + ] + }, + { + "cell_type": "markdown", + "id": "f28e4793", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a4fd93c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9490ec2c", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "f9dcbbb0", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75480b68", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "30eb1afc", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09be0d5c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "7b61f11b", + "metadata": {}, + "source": [ + "## Launch AEDT with Circuit\n", + "\n", + "Launch AEDT in graphical mode. Instantite an instance of the ``Circuit`` class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246ad1a3", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(temp_folder.name, \"SubcircuitExampl.aedt\"),\n", + " design=\"SimpleExample\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "circuit.modeler.schematic_units = \"mil\"" + ] + }, + { + "cell_type": "markdown", + "id": "ed3dc217", + "metadata": {}, + "source": [ + "## Add subcircuit\n", + "\n", + "Add a new subcircuit to the previously created circuit design, creating a\n", + "child circuit. Push this child circuit down into the child subcircuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16c15bcb", + "metadata": {}, + "outputs": [], + "source": [ + "subcircuit = circuit.modeler.schematic.create_subcircuit(location=[0.0, 0.0])\n", + "subcircuit_name = subcircuit.composed_name\n", + "circuit.push_down(subcircuit)" + ] + }, + { + "cell_type": "markdown", + "id": "43366349", + "metadata": {}, + "source": [ + "## Parametrize subcircuit\n", + "\n", + "Parametrize the subcircuit and add a resistor, inductor, and a capacitor with\n", + "parameter values. Components are connected in series,\n", + "and the focus is changed to the parent schematic using\n", + "the ``pop_up()`` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6419f132", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.variable_manager.set_variable(name=\"R_val\", expression=\"35ohm\")\n", + "circuit.variable_manager.set_variable(name=\"L_val\", expression=\"1e-7H\")\n", + "circuit.variable_manager.set_variable(name=\"C_val\", expression=\"5e-10F\")\n", + "p1 = circuit.modeler.schematic.create_interface_port(name=\"In\")\n", + "r1 = circuit.modeler.schematic.create_resistor(value=\"R_val\")\n", + "l1 = circuit.modeler.schematic.create_inductor(value=\"L_val\")\n", + "c1 = circuit.modeler.schematic.create_capacitor(value=\"C_val\")\n", + "p2 = circuit.modeler.schematic.create_interface_port(name=\"Out\")\n", + "circuit.modeler.schematic.connect_components_in_series(\n", + " assignment=[p1, r1, l1, c1, p2], use_wire=True\n", + ")\n", + "circuit.pop_up()" + ] + }, + { + "cell_type": "markdown", + "id": "ef63063c", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d3e584c", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 5 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(5)" + ] + }, + { + "cell_type": "markdown", + "id": "41c72035", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb97736f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/index.rst.txt b/version/dev/_sources/examples/high_frequency/index.rst.txt new file mode 100644 index 00000000..53690eff --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/index.rst.txt @@ -0,0 +1,95 @@ +High frequency +============== + +These end-to-end examples show how to use PyAEDT for high-frequency applications. + + +.. grid:: 2 + + .. grid-item-card:: Antenna + :padding: 2 2 2 2 + :link: antenna/index + :link-type: doc + + .. image:: antenna/_static/array.png + :alt: Antenna + :width: 250px + :height: 200px + :align: center + + Antenna examples + + .. grid-item-card:: IC-Package-PCB + :padding: 2 2 2 2 + :link: layout/index + :link-type: doc + + .. image:: ./_static/layout.png + :alt: PCB + :width: 250px + :height: 200px + :align: center + + Layout automation examples + + .. grid-item-card:: Radio frequency and millimeter wave + :padding: 2 2 2 2 + :link: radiofrequency_mmwave/index + :link-type: doc + + .. image:: ./_static/wgf.png + :alt: Filter + :width: 250px + :height: 200px + :align: center + + Radio frequency and millimeter wave examples + + .. grid-item-card:: EMC + :padding: 2 2 2 2 + :link: emc/index + :link-type: doc + + .. image:: ./_static/emc.png + :alt: Busbar + :width: 250px + :height: 200px + :align: center + + EMC examples + + .. grid-item-card:: Multiphysics + :padding: 2 2 2 2 + :link: multiphysics/index + :link-type: doc + + .. image:: ./_static/pcb_stress.png + :alt: Stress PCB + :width: 250px + :height: 200px + :align: center + + Multiphysics examples + + .. grid-item-card:: Report + :padding: 2 2 2 2 + :link: ../aedt_general/report/index + :link-type: doc + + .. image:: ../aedt_general/_static/touchstone.png + :alt: Components + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some report capabilities. + + .. toctree:: + :hidden: + + antenna/index + radiofrequency_mmwave/index + layout/index + emc/index + multiphysics/index + ../aedt_general/report/index diff --git a/version/dev/_sources/examples/high_frequency/layout/gui_manipulation.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/gui_manipulation.ipynb.txt new file mode 100644 index 00000000..37d7c94a --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/gui_manipulation.ipynb.txt @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e1930ff6", + "metadata": {}, + "source": [ + "# HFSS Layout UI modification\n", + "\n", + "This example shows how to modify the HFSS 3D Layout UI.\n", + "\n", + "\n", + "Keywords: **HFSS 3D Layout**, **UI**, **user interface**." + ] + }, + { + "cell_type": "markdown", + "id": "e9611391", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efaa6579", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import sys\n", + "import tempfile\n", + "import time\n", + "\n", + "from ansys.aedt.core import Hfss3dLayout\n", + "from ansys.aedt.core.downloads import download_file\n" + ] + }, + { + "cell_type": "markdown", + "id": "6921b412", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f82dc6d0", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = True # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "37ec6dbf", + "metadata": {}, + "source": [ + "Check if AEDT is launched in graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ca69403", + "metadata": {}, + "outputs": [], + "source": [ + "if not NG_MODE:\n", + " print(\"Warning: This example requires graphical mode enabled.\")\n", + " sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "bd9a2cd4", + "metadata": {}, + "source": [ + "Download example board." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fb5e761", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "aedb = download_file(source=\"edb/ANSYS-HSD_V1.aedb\", destination=temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "1c40140f", + "metadata": {}, + "source": [ + "## Launch HFSS 3D Layout\n", + "\n", + "Initialize AEDT and launch HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bca9235", + "metadata": {}, + "outputs": [], + "source": [ + "h3d = Hfss3dLayout(aedb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True)\n", + "h3d.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "01022567", + "metadata": {}, + "source": [ + "## Net visibility\n", + "Hide all nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e7cd9d9", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.modeler.change_net_visibility(visible=False)" + ] + }, + { + "cell_type": "markdown", + "id": "02132849", + "metadata": {}, + "source": [ + "Show two specified nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7abf16f", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.modeler.change_net_visibility([\"5V\", \"1V0\"], visible=True)" + ] + }, + { + "cell_type": "markdown", + "id": "35555513", + "metadata": {}, + "source": [ + "Show all layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "878a5a73", + "metadata": {}, + "outputs": [], + "source": [ + "for layer in h3d.modeler.layers.all_signal_layers:\n", + " layer.is_visible = True" + ] + }, + { + "cell_type": "markdown", + "id": "1ebcd5cc", + "metadata": {}, + "source": [ + "Change the layer color." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec1bb8c5", + "metadata": {}, + "outputs": [], + "source": [ + "layer = h3d.modeler.layers.layers[h3d.modeler.layers.layer_id(\"1_Top\")]\n", + "layer.set_layer_color(0, 255, 0)\n", + "h3d.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "7a1c5121", + "metadata": {}, + "source": [ + "## Disable component visibility" + ] + }, + { + "cell_type": "markdown", + "id": "28eb3044", + "metadata": {}, + "source": [ + "Disable component visibility for the ``\"1_Top\"`` and ``\"16_Bottom\"`` layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "230cffa8", + "metadata": {}, + "outputs": [], + "source": [ + "top = h3d.modeler.layers.layers[h3d.modeler.layers.layer_id(\"1_Top\")]\n", + "top.is_visible_component = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19f74803", + "metadata": {}, + "outputs": [], + "source": [ + "bot = h3d.modeler.layers.layers[h3d.modeler.layers.layer_id(\"16_Bottom\")]\n", + "bot.is_visible_component = False" + ] + }, + { + "cell_type": "markdown", + "id": "2e4cb528", + "metadata": {}, + "source": [ + "## Display the layout\n", + "\n", + "Fit all so that you can visualize all." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e95f3b8", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "1cb46566", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c344119", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.save_project()\n", + "h3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "0f0a88ac", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16505483", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/index.rst.txt b/version/dev/_sources/examples/high_frequency/layout/index.rst.txt new file mode 100644 index 00000000..73a67978 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/index.rst.txt @@ -0,0 +1,80 @@ +IC-Package-PCB +============== + +These examples use PyAEDT to show some layout applications. + + +.. grid:: 2 + + .. grid-item-card:: Layout preprocessing + :padding: 2 2 2 2 + :link: https://edb.docs.pyansys.com/version/stable/examples/legacy_standalone/index.html + :link-type: url + + .. image:: _static/pyedb.png + :alt: PyEDB + :width: 250px + :height: 200px + :align: center + + Links to examples in the AEDT documentation that show how to use the legacy PyEDB API as a standalone package. + + .. grid-item-card:: PyEDB configuration files + :padding: 2 2 2 2 + :link: https://edb.docs.pyansys.com/version/stable/examples/use_configuration/index.html + :link-type: url + + .. image:: _static/pyedb2.png + :alt: PyEDB2 + :width: 250px + :height: 200px + :align: center + + Links to examples in the PyAEDT documentation that show how to use PyEDB configuration files. + + .. grid-item-card:: Power integrity + :padding: 2 2 2 2 + :link: power_integrity/index + :link-type: doc + + .. image:: _static/power_integrity.png + :alt: Power + :width: 250px + :height: 200px + :align: center + + Provides power integrity examples. + + .. grid-item-card:: Signal integrity + :padding: 2 2 2 2 + :link: signal_integrity/index + :link-type: doc + + .. image:: _static/signal_integrity.png + :alt: Signal + :width: 250px + :height: 200px + :align: center + + Provides signal integrity examples + + .. grid-item-card:: HFSS 3D Layout GUI modificatation + :padding: 2 2 2 2 + :link: gui_manipulation + :link-type: doc + + .. image:: _static/user_interface.png + :alt: UI 3D Layout + :width: 250px + :height: 200px + :align: center + + Provides HFSS 3D Layout GUI modification examples. + + + .. toctree:: + :hidden: + + power_integrity/index + signal_integrity/index + gui_manipulation \ No newline at end of file diff --git a/version/dev/_sources/examples/high_frequency/layout/power_integrity/ac_q3d.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/power_integrity/ac_q3d.ipynb.txt new file mode 100644 index 00000000..ceae0fe5 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/power_integrity/ac_q3d.ipynb.txt @@ -0,0 +1,438 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6dcc20ef", + "metadata": {}, + "source": [ + "# PCB AC analysis" + ] + }, + { + "cell_type": "markdown", + "id": "9d7bc18d", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a design in\n", + "Q3D Extractor and run a simulation starting from an EDB project.\n", + "\n", + "Keywords: **Q3D**, **PCB**." + ] + }, + { + "cell_type": "markdown", + "id": "3c13b423", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25e45c7d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38d7d4cb", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import pyedb" + ] + }, + { + "cell_type": "markdown", + "id": "18e666be", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1bd69da", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "ed8e16e1", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b77ba6b6", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "40ef00c8", + "metadata": {}, + "source": [ + "## Set up project files and path\n", + "\n", + "Download needed project file and set up temporary project directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b150423a", + "metadata": {}, + "outputs": [], + "source": [ + "project_dir = os.path.join(temp_folder.name, \"edb\")\n", + "aedb_project = ansys.aedt.core.downloads.download_file(\n", + " source=\"edb/ANSYS-HSD_V1.aedb\", destination=project_dir\n", + ")\n", + "\n", + "project_name = os.path.join(temp_folder.name, \"HSD\")\n", + "output_edb = os.path.join(project_dir, project_name + \".aedb\")\n", + "output_q3d = os.path.join(project_dir, project_name + \"_q3d.aedt\")" + ] + }, + { + "cell_type": "markdown", + "id": "1ac97576", + "metadata": {}, + "source": [ + "## Open EDB and create cutout\n", + "\n", + "Open the EDB project and create a cutout on the selected nets\n", + "before exporting to Q3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "419ee4c0", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "edb = pyedb.Edb(aedb_project, edbversion=AEDT_VERSION)\n", + "cutout_points = edb.cutout(\n", + " [\"CLOCK_I2C_SCL\", \"CLOCK_I2C_SDA\"],\n", + " [\"GND\"],\n", + " output_aedb_path=output_edb,\n", + " use_pyaedt_extent_computing=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9ba2a930", + "metadata": {}, + "source": [ + "## Identify locations of pins\n", + "\n", + "Identify $(x,y)$ pin locations on the components to define where to assign sources\n", + "and sinks for Q3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef0eb2be", + "metadata": {}, + "outputs": [], + "source": [ + "pin_u13_scl = [\n", + " i for i in edb.components[\"U13\"].pins.values() if i.net_name == \"CLOCK_I2C_SCL\"\n", + "]\n", + "pin_u1_scl = [\n", + " i for i in edb.components[\"U1\"].pins.values() if i.net_name == \"CLOCK_I2C_SCL\"\n", + "]\n", + "pin_u13_sda = [\n", + " i for i in edb.components[\"U13\"].pins.values() if i.net_name == \"CLOCK_I2C_SDA\"\n", + "]\n", + "pin_u1_sda = [\n", + " i for i in edb.components[\"U1\"].pins.values() if i.net_name == \"CLOCK_I2C_SDA\"\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "fd845bf1", + "metadata": {}, + "source": [ + "## Append Z elevation positions\n", + "\n", + "> **Note:** The factor 1000 converts from meters to millimeters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6567faab", + "metadata": {}, + "outputs": [], + "source": [ + "location_u13_scl = [i * 1000 for i in pin_u13_scl[0].position]\n", + "location_u13_scl.append(edb.components[\"U13\"].upper_elevation * 1000)\n", + "\n", + "location_u1_scl = [i * 1000 for i in pin_u1_scl[0].position]\n", + "location_u1_scl.append(edb.components[\"U1\"].upper_elevation * 1000)\n", + "\n", + "location_u13_sda = [i * 1000 for i in pin_u13_sda[0].position]\n", + "location_u13_sda.append(edb.components[\"U13\"].upper_elevation * 1000)\n", + "\n", + "location_u1_sda = [i * 1000 for i in pin_u1_sda[0].position]\n", + "location_u1_sda.append(edb.components[\"U1\"].upper_elevation * 1000)" + ] + }, + { + "cell_type": "markdown", + "id": "3e5cb872", + "metadata": {}, + "source": [ + "## Save and close EDB\n", + "\n", + "Save and close EDB. Then, open the EDB project in HFSS 3D Layout to generate the 3D model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02b5d481", + "metadata": {}, + "outputs": [], + "source": [ + "edb.save_edb()\n", + "edb.close_edb()\n", + "\n", + "h3d = ansys.aedt.core.Hfss3dLayout(\n", + " output_edb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "370a64f1", + "metadata": {}, + "source": [ + "## Set up the Q3D Project\n", + "\n", + "Use HFSS 3D Layout to export the model to Q3D Extractor. The named parameter\n", + "``keep_net_name=True`` ensures that net names are retained when the model is exported from HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39ef72f4", + "metadata": {}, + "outputs": [], + "source": [ + "setup = h3d.create_setup()\n", + "setup.export_to_q3d(output_q3d, keep_net_name=True)\n", + "h3d.close_project()\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "87291679", + "metadata": {}, + "source": [ + "Open the newly created Q3D project and display the layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ac741cc", + "metadata": {}, + "outputs": [], + "source": [ + "q3d = ansys.aedt.core.Q3d(output_q3d, version=AEDT_VERSION)\n", + "q3d.plot(\n", + " show=False,\n", + " assignment=[\"CLOCK_I2C_SCL\", \"CLOCK_I2C_SDA\"],\n", + " output_file=os.path.join(temp_folder.name, \"Q3D.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e4ab7672", + "metadata": {}, + "source": [ + "Use the previously calculated positions to identify faces and\n", + "assign sources and sinks on nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8ac5adc", + "metadata": {}, + "outputs": [], + "source": [ + "f1 = q3d.modeler.get_faceid_from_position(location_u13_scl, assignment=\"CLOCK_I2C_SCL\")\n", + "q3d.source(f1, net_name=\"CLOCK_I2C_SCL\")\n", + "f1 = q3d.modeler.get_faceid_from_position(location_u13_sda, assignment=\"CLOCK_I2C_SDA\")\n", + "q3d.source(f1, net_name=\"CLOCK_I2C_SDA\")\n", + "f1 = q3d.modeler.get_faceid_from_position(location_u1_scl, assignment=\"CLOCK_I2C_SCL\")\n", + "q3d.sink(f1, net_name=\"CLOCK_I2C_SCL\")\n", + "f1 = q3d.modeler.get_faceid_from_position(location_u1_sda, assignment=\"CLOCK_I2C_SDA\")\n", + "q3d.sink(f1, net_name=\"CLOCK_I2C_SDA\")" + ] + }, + { + "cell_type": "markdown", + "id": "41bb22a5", + "metadata": {}, + "source": [ + "Define the solution setup and the frequency sweep ranging from DC to 2GHz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "753342a3", + "metadata": {}, + "outputs": [], + "source": [ + "setup = q3d.create_setup()\n", + "setup.dc_enabled = True\n", + "setup.capacitance_enabled = False\n", + "sweep = setup.add_sweep()\n", + "sweep.add_subrange(\n", + " \"LinearStep\", 0, end=2, count=0.05, unit=\"GHz\", save_single_fields=False, clear=True\n", + ")\n", + "setup.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "a5d977c6", + "metadata": {}, + "source": [ + "## Solve\n", + "\n", + "Compute AC inductance and resistance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "633e5e19", + "metadata": {}, + "outputs": [], + "source": [ + "traces_acl = q3d.post.available_report_quantities(quantities_category=\"ACL Matrix\")\n", + "solution = q3d.post.get_solution_data(traces_acl)" + ] + }, + { + "cell_type": "markdown", + "id": "8a1be484", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Plot AC inductance and resistance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc85f1da", + "metadata": {}, + "outputs": [], + "source": [ + "solution.plot()\n", + "traces_acr = q3d.post.available_report_quantities(quantities_category=\"ACR Matrix\")\n", + "solution2 = q3d.post.get_solution_data(traces_acr)\n", + "solution2.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "7ceaa592", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7208c401", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.save_project()\n", + "q3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c4d3f264", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32a14394", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir.ipynb.txt new file mode 100644 index 00000000..d0024655 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir.ipynb.txt @@ -0,0 +1,555 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "22e47e88", + "metadata": {}, + "source": [ + "# DC IR analysis\n", + "This example shows how to configure EDB for DC IR analysis and load EDB into the HFSS 3D Layout UI for analysis and\n", + "postprocessing.\n", + "\n", + "- Set up EDB:\n", + "\n", + " - Edit via padstack.\n", + " - Assign SPICE model to components.\n", + " - Create pin groups.\n", + " - Create voltage and current sources.\n", + " - Create SIwave DC analysis.\n", + " - Create cutout.\n", + "\n", + "- Import EDB into HFSS 3D Layout:\n", + "\n", + " - Analyze.\n", + " - Get DC IR analysis results.\n", + "\n", + "Keywords: **HFSS 3D Layout**, **DC IR**." + ] + }, + { + "cell_type": "markdown", + "id": "2bf9ca81", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e9a16f9", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae9ea4b1", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.downloads import download_file\n", + "from pyedb import Edb" + ] + }, + { + "cell_type": "markdown", + "id": "6fe964fc", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff1cc0ed", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "d8144e5f", + "metadata": {}, + "source": [ + "Download example board." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4caf82b8", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "aedb = download_file(source=\"edb/ANSYS-HSD_V1.aedb\", destination=temp_folder.name)\n", + "download_file(\n", + " source=\"spice\", name=\"ferrite_bead_BLM15BX750SZ1.mod\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "17af0ea8", + "metadata": {}, + "source": [ + "## Create configuration file\n", + "This example uses a configuration file to set up the layout for analysis.\n", + "Initialize and create an empty dictionary to host all configurations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15d8f4fa", + "metadata": {}, + "outputs": [], + "source": [ + "cfg = dict()" + ] + }, + { + "cell_type": "markdown", + "id": "81727fd3", + "metadata": {}, + "source": [ + "Define model library paths." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49abb96d", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"general\"] = {\n", + " \"s_parameter_library\": os.path.join(temp_folder.name, \"touchstone\"),\n", + " \"spice_model_library\": os.path.join(temp_folder.name, \"spice\"),\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "12f7a02f", + "metadata": {}, + "source": [ + "### Change via hole size and plating thickness" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cc51c8d", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"padstacks\"] = {\n", + " \"definitions\": [\n", + " {\"name\": \"v40h15-3\", \"hole_diameter\": \"0.2mm\", \"hole_plating_thickness\": \"25um\"}\n", + " ],\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "b2168645", + "metadata": {}, + "source": [ + "### Assign SPICE models" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb47de8a", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"spice_models\"] = [\n", + " {\n", + " \"name\": \"ferrite_bead_BLM15BX750SZ1\", # Give a name to the SPICE Mode.\n", + " \"component_definition\": \"COIL-1008CS_V\", # Part name of the components\n", + " \"file_path\": \"ferrite_bead_BLM15BX750SZ1.mod\", # File name or full file path to the SPICE file.\n", + " \"sub_circuit_name\": \"BLM15BX750SZ1\",\n", + " \"apply_to_all\": True, # If True, SPICE model is to be assigned to all components share the same part name.\n", + " # If False, only assign SPICE model to components in \"components\".\n", + " \"components\": [],\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "94e26ea3", + "metadata": {}, + "source": [ + "### Create voltage source\n", + "Create a voltage source from a net." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32cd7310", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"sources\"] = [\n", + " {\n", + " \"name\": \"VSOURCE_5V\",\n", + " \"reference_designator\": \"U4\",\n", + " \"type\": \"voltage\",\n", + " \"magnitude\": 5,\n", + " \"positive_terminal\": {\"net\": \"5V\"},\n", + " \"negative_terminal\": {\"net\": \"GND\"},\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "c081e324", + "metadata": {}, + "source": [ + "### Create current sources\n", + "Create current sources between the net and pin group." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58358e54", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"pin_groups\"] = [{\"name\": \"J5_GND\", \"reference_designator\": \"J5\", \"net\": \"GND\"}]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c0fa8477", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"sources\"].append(\n", + " {\n", + " \"name\": \"J5_VCCR\",\n", + " \"reference_designator\": \"J5\",\n", + " \"type\": \"current\",\n", + " \"magnitude\": 0.5,\n", + " \"positive_terminal\": {\"net\": \"SFPA_VCCR\"},\n", + " \"negative_terminal\": {\n", + " \"pin_group\": \"J5_GND\" # Defined in \"pin_groups\" section.\n", + " },\n", + " }\n", + ")\n", + "cfg[\"sources\"].append(\n", + " {\n", + " \"name\": \"J5_VCCT\",\n", + " \"reference_designator\": \"J5\",\n", + " \"type\": \"current\",\n", + " \"magnitude\": 0.5,\n", + " \"positive_terminal\": {\"net\": \"SFPA_VCCT\"},\n", + " \"negative_terminal\": {\n", + " \"pin_group\": \"J5_GND\" # Defined in \"pin_groups\" section.\n", + " },\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ebaee1ce", + "metadata": {}, + "source": [ + "### Create SIwave DC analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2abc308e", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"setups\"] = [{\"name\": \"siwave_dc\", \"type\": \"siwave_dc\", \"dc_slider_position\": 0}]" + ] + }, + { + "cell_type": "markdown", + "id": "f759b3c0", + "metadata": {}, + "source": [ + "### Define cutout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1173205d", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"operations\"] = {\n", + " \"cutout\": {\n", + " \"signal_list\": [\"SFPA_VCCR\", \"SFPA_VCCT\", \"5V\"],\n", + " \"reference_list\": [\"GND\"],\n", + " \"extent_type\": \"ConvexHull\",\n", + " \"expansion_size\": 0.002,\n", + " \"use_round_corner\": False,\n", + " \"output_aedb_path\": \"\",\n", + " \"open_cutout_at_end\": True,\n", + " \"use_pyaedt_cutout\": True,\n", + " \"number_of_threads\": 4,\n", + " \"use_pyaedt_extent_computing\": True,\n", + " \"extent_defeature\": 0,\n", + " \"remove_single_pin_components\": False,\n", + " \"custom_extent\": \"\",\n", + " \"custom_extent_units\": \"mm\",\n", + " \"include_partial_instances\": False,\n", + " \"keep_voids\": True,\n", + " \"check_terminals\": False,\n", + " \"include_pingroups\": False,\n", + " \"expansion_factor\": 0,\n", + " \"maximum_iterations\": 10,\n", + " \"preserve_components_with_model\": False,\n", + " \"simple_pad_check\": True,\n", + " \"keep_lines_as_path\": False,\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "a0620dc0", + "metadata": {}, + "source": [ + "### Save configuration as a JSON file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4d8ca30", + "metadata": {}, + "outputs": [], + "source": [ + "pi_json = os.path.join(temp_folder.name, \"pi.json\")\n", + "with open(pi_json, \"w\") as f:\n", + " json.dump(cfg, f, indent=4, ensure_ascii=False)" + ] + }, + { + "cell_type": "markdown", + "id": "fc7322f8", + "metadata": {}, + "source": [ + "## Load configuration into EDB" + ] + }, + { + "cell_type": "markdown", + "id": "ffe67d63", + "metadata": {}, + "source": [ + "Load the configuration from the JSON file into EDB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5867bdc7", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp = Edb(aedb, edbversion=AEDT_VERSION)\n", + "edbapp.configuration.load(config_file=pi_json)\n", + "edbapp.configuration.run()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b43bd0d", + "metadata": {}, + "outputs": [], + "source": [ + "# # Load configuration into EDB\n", + "edbapp.nets.plot(None, None, color_by_net=True)" + ] + }, + { + "cell_type": "markdown", + "id": "0313a79f", + "metadata": {}, + "source": [ + "## Save and close EDB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1f6cde3", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.save()\n", + "edbapp.close()" + ] + }, + { + "cell_type": "markdown", + "id": "1f2443ba", + "metadata": {}, + "source": [ + "The configured EDB file is saved in the temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56ff3f32", + "metadata": {}, + "outputs": [], + "source": [ + "print(temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "b952f0e4", + "metadata": {}, + "source": [ + "## Analyze DCIR with SIwave\n", + "\n", + "The HFSS 3D Layout interface to SIwave is used to open the EDB and run the DCIR analysis\n", + "using SIwave" + ] + }, + { + "cell_type": "markdown", + "id": "6cab6f0a", + "metadata": {}, + "source": [ + "### Load EDB into HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "242b5946", + "metadata": {}, + "outputs": [], + "source": [ + "siw = ansys.aedt.core.Hfss3dLayout(\n", + " aedb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9b5b018c", + "metadata": {}, + "source": [ + "### Analyze" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c2e4c7f", + "metadata": {}, + "outputs": [], + "source": [ + "siw.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "79e0531e", + "metadata": {}, + "source": [ + "### Get DC IR results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f5522b9", + "metadata": {}, + "outputs": [], + "source": [ + "siw.get_dcir_element_data_current_source(\"siwave_dc\")" + ] + }, + { + "cell_type": "markdown", + "id": "dfac9d93", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad733e4e", + "metadata": {}, + "outputs": [], + "source": [ + "siw.save_project()\n", + "siw.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "13b48f4c", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c51e58b4", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir_q3d.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir_q3d.ipynb.txt new file mode 100644 index 00000000..54c6e092 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/power_integrity/dcir_q3d.ipynb.txt @@ -0,0 +1,627 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "34e761a3", + "metadata": {}, + "source": [ + "# PCB DCIR analysis\n", + "\n", + "This example shows how to use PyAEDT to create a design in\n", + "Q3D Extractor and run a DC IR drop simulation starting from an EDB project.\n", + "\n", + "Keywords: **Q3D**, **layout**, **DCIR**." + ] + }, + { + "cell_type": "markdown", + "id": "319c4806", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2f61d46", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca039a9d", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import pyedb" + ] + }, + { + "cell_type": "markdown", + "id": "f915efd0", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e60c80fd", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False" + ] + }, + { + "cell_type": "markdown", + "id": "83d93805", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcfbc971", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "# ## Set up project files and path\n", + "#\n", + "# Download needed project file and set up temporary project directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51d83e48", + "metadata": {}, + "outputs": [], + "source": [ + "aedb_project = ansys.aedt.core.downloads.download_file(\n", + " \"edb/ANSYS-HSD_V1.aedb\", destination=temp_folder.name\n", + ")\n", + "coil = ansys.aedt.core.downloads.download_file(\n", + " source=\"inductance_3d_component\",\n", + " name=\"air_coil.a3dcomp\",\n", + " destination=temp_folder.name,\n", + ")\n", + "res = ansys.aedt.core.downloads.download_file(\n", + " source=\"resistors\", name=\"Res_0402.a3dcomp\", destination=temp_folder.name\n", + ")\n", + "project_name = \"HSD\"\n", + "output_edb = os.path.join(temp_folder.name, project_name + \".aedb\")\n", + "output_q3d = os.path.join(temp_folder.name, project_name + \"_q3d.aedt\")" + ] + }, + { + "cell_type": "markdown", + "id": "28c65c4f", + "metadata": {}, + "source": [ + "## Open EDB project\n", + "\n", + "Open the EDB project and create a cutout on the selected nets\n", + "before exporting to Q3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b6105ee", + "metadata": {}, + "outputs": [], + "source": [ + "edb = pyedb.Edb(aedb_project, edbversion=AEDT_VERSION)\n", + "signal_nets = [\"1.2V_AVDLL_PLL\", \"1.2V_AVDDL\", \"1.2V_DVDDL\", \"NetR106_1\"]\n", + "ground_nets = [\"GND\"]\n", + "cutout_points = edb.cutout(\n", + " signal_list=signal_nets,\n", + " reference_list=ground_nets,\n", + " output_aedb_path=output_edb,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7f950cc1", + "metadata": {}, + "source": [ + "## Identify pin positions\n", + "\n", + "Identify [x,y] pin locations on the components to define where to assign sources\n", + "and sinks for Q3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34c2c6b9", + "metadata": {}, + "outputs": [], + "source": [ + "pin_u11_scl = [\n", + " i for i in edb.components[\"U11\"].pins.values() if i.net_name == \"1.2V_AVDLL_PLL\"\n", + "]\n", + "pin_u9_1 = [i for i in edb.components[\"U9\"].pins.values() if i.net_name == \"1.2V_AVDDL\"]\n", + "pin_u9_2 = [i for i in edb.components[\"U9\"].pins.values() if i.net_name == \"1.2V_DVDDL\"]\n", + "pin_u11_r106 = [\n", + " i for i in edb.components[\"U11\"].pins.values() if i.net_name == \"NetR106_1\"\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "fc057d6c", + "metadata": {}, + "source": [ + "## Append Z Positions\n", + "\n", + "Compute the Q3D 3D position. The units in EDB are meters so the\n", + "factor 1000 converts from meters to millimeters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d119a5d", + "metadata": {}, + "outputs": [], + "source": [ + "location_u11_scl = [i * 1000 for i in pin_u11_scl[0].position]\n", + "location_u11_scl.append(edb.components[\"U11\"].upper_elevation * 1000)\n", + "\n", + "location_u9_1_scl = [i * 1000 for i in pin_u9_1[0].position]\n", + "location_u9_1_scl.append(edb.components[\"U9\"].upper_elevation * 1000)\n", + "\n", + "location_u9_2_scl = [i * 1000 for i in pin_u9_2[0].position]\n", + "location_u9_2_scl.append(edb.components[\"U9\"].upper_elevation * 1000)\n", + "\n", + "location_u11_r106 = [i * 1000 for i in pin_u11_r106[0].position]\n", + "location_u11_r106.append(edb.components[\"U11\"].upper_elevation * 1000)" + ] + }, + { + "cell_type": "markdown", + "id": "c462f95d", + "metadata": {}, + "source": [ + "## Identify pin positions for 3D components\n", + "\n", + "Identify the pin positions where 3D components of passives are to be added." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1bcff2e", + "metadata": {}, + "outputs": [], + "source": [ + "location_l2_1 = [i * 1000 for i in edb.components[\"L2\"].pins[\"1\"].position]\n", + "location_l2_1.append(edb.components[\"L2\"].upper_elevation * 1000)\n", + "location_l4_1 = [i * 1000 for i in edb.components[\"L4\"].pins[\"1\"].position]\n", + "location_l4_1.append(edb.components[\"L4\"].upper_elevation * 1000)\n", + "\n", + "location_r106_1 = [i * 1000 for i in edb.components[\"R106\"].pins[\"1\"].position]\n", + "location_r106_1.append(edb.components[\"R106\"].upper_elevation * 1000)" + ] + }, + { + "cell_type": "markdown", + "id": "0d191c1f", + "metadata": {}, + "source": [ + "## Save and close EDB\n", + "\n", + "Save and close EDB. Then, open EDT in HFSS 3D Layout to generate the 3D model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05a9590f", + "metadata": {}, + "outputs": [], + "source": [ + "edb.save_edb()\n", + "edb.close_edb()\n", + "time.sleep(3)\n", + "\n", + "h3d = ansys.aedt.core.Hfss3dLayout(\n", + " output_edb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fd003420", + "metadata": {}, + "source": [ + "## Export to Q3D\n", + "\n", + "Create a dummy setup and export the layout to Q3D.\n", + "The ``keep_net_name`` parameter reassigns Q3D net names from HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "686260c5", + "metadata": {}, + "outputs": [], + "source": [ + "setup = h3d.create_setup()\n", + "setup.export_to_q3d(output_q3d, keep_net_name=True)\n", + "h3d.close_project()\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "f074f4a2", + "metadata": {}, + "source": [ + "## Open Q3D\n", + "\n", + "Launch the newly created Q3D project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fafb1f94", + "metadata": {}, + "outputs": [], + "source": [ + "q3d = ansys.aedt.core.Q3d(output_q3d, version=AEDT_VERSION)\n", + "q3d.modeler.delete(\"GND\")\n", + "q3d.modeler.delete(\"16_Bottom_L6\")\n", + "q3d.delete_all_nets()" + ] + }, + { + "cell_type": "markdown", + "id": "d497d4f7", + "metadata": {}, + "source": [ + "## Insert inductors\n", + "\n", + "Create coordinate systems and place 3D component inductors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c55c4e0d", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.modeler.create_coordinate_system(location_l2_1, name=\"L2\")\n", + "comp = q3d.modeler.insert_3d_component(coil, coordinate_system=\"L2\")\n", + "comp.rotate(q3d.AXIS.Z, -90)\n", + "comp.parameters[\"n_turns\"] = \"3\"\n", + "comp.parameters[\"d_wire\"] = \"100um\"\n", + "q3d.modeler.set_working_coordinate_system(\"Global\")\n", + "q3d.modeler.create_coordinate_system(location_l4_1, name=\"L4\")\n", + "comp2 = q3d.modeler.insert_3d_component(coil, coordinate_system=\"L4\")\n", + "comp2.rotate(q3d.AXIS.Z, -90)\n", + "comp2.parameters[\"n_turns\"] = \"3\"\n", + "comp2.parameters[\"d_wire\"] = \"100um\"\n", + "q3d.modeler.set_working_coordinate_system(\"Global\")\n", + "\n", + "q3d.modeler.set_working_coordinate_system(\"Global\")\n", + "q3d.modeler.create_coordinate_system(location_r106_1, name=\"R106\")\n", + "comp3 = q3d.modeler.insert_3d_component(\n", + " res, geometry_parameters={\"$Resistance\": 2000}, coordinate_system=\"R106\"\n", + ")\n", + "comp3.rotate(q3d.AXIS.Z, -90)\n", + "\n", + "q3d.modeler.set_working_coordinate_system(\"Global\")" + ] + }, + { + "cell_type": "markdown", + "id": "cce17ca9", + "metadata": {}, + "source": [ + "## Delete dielectrics\n", + "\n", + "Delete all dielectric objects since they are not needed in DC analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "872c4934", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.modeler.delete(q3d.modeler.get_objects_by_material(\"Megtron4\"))\n", + "q3d.modeler.delete(q3d.modeler.get_objects_by_material(\"Megtron4_2\"))\n", + "q3d.modeler.delete(q3d.modeler.get_objects_by_material(\"Megtron4_3\"))\n", + "q3d.modeler.delete(q3d.modeler.get_objects_by_material(\"Solder Resist\"))\n", + "\n", + "objs_copper = q3d.modeler.get_objects_by_material(\"copper\")\n", + "objs_copper_names = [i.name for i in objs_copper]\n", + "q3d.plot(\n", + " show=False,\n", + " assignment=objs_copper_names,\n", + " plot_as_separate_objects=False,\n", + " output_file=os.path.join(temp_folder.name, \"Q3D.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9d837070", + "metadata": {}, + "source": [ + "## Assign source and sink\n", + "\n", + "Use previously calculated positions to identify faces. Select the net ``1_Top`` and\n", + "assign sources and sinks on nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d347d44", + "metadata": {}, + "outputs": [], + "source": [ + "sink_f = q3d.modeler.create_circle(q3d.PLANE.XY, location_u11_scl, 0.1)\n", + "source_f1 = q3d.modeler.create_circle(q3d.PLANE.XY, location_u9_1_scl, 0.1)\n", + "source_f2 = q3d.modeler.create_circle(q3d.PLANE.XY, location_u9_2_scl, 0.1)\n", + "source_f3 = q3d.modeler.create_circle(q3d.PLANE.XY, location_u11_r106, 0.1)\n", + "sources_objs = [source_f1, source_f2, source_f3]\n", + "\n", + "q3d.auto_identify_nets()\n", + "\n", + "identified_net = q3d.nets[0]\n", + "\n", + "q3d.sink(sink_f, net_name=identified_net)\n", + "\n", + "source1 = q3d.source(source_f1, net_name=identified_net)\n", + "\n", + "source2 = q3d.source(source_f2, net_name=identified_net)\n", + "source3 = q3d.source(source_f3, net_name=identified_net)\n", + "sources_bounds = [source1, source2, source3]\n", + "\n", + "q3d.edit_sources(\n", + " dcrl={\n", + " \"{}:{}\".format(source1.props[\"Net\"], source1.name): \"-1.0A\",\n", + " \"{}:{}\".format(source2.props[\"Net\"], source2.name): \"-1.0A\",\n", + " \"{}:{}\".format(source2.props[\"Net\"], source3.name): \"-1.0A\",\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "64551301", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup and a frequency sweep from DC to 2GHz.\n", + "Then, analyze the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a99a737", + "metadata": {}, + "outputs": [], + "source": [ + "setup = q3d.create_setup()\n", + "setup.dc_enabled = True\n", + "setup.capacitance_enabled = False\n", + "setup.ac_rl_enabled = False\n", + "setup.props[\"SaveFields\"] = True\n", + "setup.props[\"DC\"][\"Cond\"][\"MaxPass\"] = 3\n", + "setup.analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "06051fa4", + "metadata": {}, + "source": [ + "## Solve setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35bd71d2", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.save_project()\n", + "q3d.analyze_setup(setup.name, cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "0db79683", + "metadata": {}, + "source": [ + "## Create a named expression\n", + "\n", + "Use PyAEDT advanced fields calculator to add from the expressions catalog the voltage drop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9c92fc7", + "metadata": {}, + "outputs": [], + "source": [ + "voltage_drop = q3d.post.fields_calculator.add_expression(\"voltage_drop\", None)" + ] + }, + { + "cell_type": "markdown", + "id": "99cc7cba", + "metadata": {}, + "source": [ + "## Create Phi plot\n", + "\n", + "Compute ACL solutions and plot them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36276833", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "plot1 = q3d.post.create_fieldplot_surface(\n", + " q3d.modeler.get_objects_by_material(\"copper\"),\n", + " quantity=voltage_drop,\n", + " intrinsics={\"Freq\": \"1GHz\"},\n", + ")\n", + "\n", + "q3d.post.plot_field_from_fieldplot(\n", + " plot1.name,\n", + " project_path=temp_folder.name,\n", + " mesh_plot=False,\n", + " image_format=\"jpg\",\n", + " view=\"isometric\",\n", + " show=False,\n", + " plot_cad_objs=False,\n", + " log_scale=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "75cc6294", + "metadata": {}, + "source": [ + "## Compute voltage on source circles\n", + "\n", + "Use PyAEDT advanced field calculator to compute the voltage on source circles and get the value\n", + "using the ``get_solution_data()`` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b86cec0f", + "metadata": {}, + "outputs": [], + "source": [ + "v_surface = {\n", + " \"name\": \"\",\n", + " \"description\": \"Maximum value of voltage on a surface\",\n", + " \"design_type\": [\"Q3D Extractor\"],\n", + " \"fields_type\": [\"DC R/L Fields\"],\n", + " \"primary_sweep\": \"Freq\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Face\", \"Sheet\"],\n", + " \"operations\": [\n", + " f\"NameOfExpression({voltage_drop})\",\n", + " \"EnterSurface('assignment')\",\n", + " \"Operation('SurfaceValue')\",\n", + " \"Operation('Maximum')\",\n", + " ],\n", + " \"report\": [\"Field_3D\"],\n", + "}\n", + "for source_circle, source_bound in zip(sources_objs, sources_bounds):\n", + " v_surface[\"name\"] = \"V{}\".format(source_bound.name)\n", + " q3d.post.fields_calculator.add_expression(v_surface, source_circle.name)\n", + "\n", + " data = q3d.post.get_solution_data(\n", + " \"V{}\".format(source_bound.name),\n", + " q3d.nominal_adaptive,\n", + " variations={\"Freq\": \"1GHz\"},\n", + " report_category=\"DC R/L Fields\",\n", + " )\n", + " if data:\n", + " print(data.data_real(\"V{}\".format(source_bound.name)))" + ] + }, + { + "cell_type": "markdown", + "id": "95fb75dc", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0b31c65", + "metadata": {}, + "outputs": [], + "source": [ + "q3d.save_project()\n", + "q3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "88c6808a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f56a2fe5", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/power_integrity/index.rst.txt b/version/dev/_sources/examples/high_frequency/layout/power_integrity/index.rst.txt new file mode 100644 index 00000000..0d324b8c --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/power_integrity/index.rst.txt @@ -0,0 +1,112 @@ +Power integrity +~~~~~~~~~~~~~~~ + +These examples use PyAEDT to show power integrity examples. + +.. grid:: 2 + + .. grid-item-card:: Power integrity analysis + :padding: 2 2 2 2 + :link: power_integrity + :link-type: doc + + .. image:: _static/power_integrity.png + :alt: Power integrity + :width: 250px + :height: 200px + :align: center + + This example shows how to use the Ansys Electronics Database (EDB) for power integrity analysis. + + .. grid-item-card:: DC IR analysis + :padding: 2 2 2 2 + :link: dcir + :link-type: doc + + .. image:: _static/dcir.png + :alt: DCIR + :width: 250px + :height: 200px + :align: center + + This example shows how to configure EDB for DC IR analysis and load EDB into the HFSS 3D Layout UI for analysis + and postprocessing. + + .. grid-item-card:: PCB DCIR analysis + :padding: 2 2 2 2 + :link: dcir_q3d + :link-type: doc + + .. image:: _static/dcir_q3d.png + :alt: DCIR + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a design in Q3D Extractor and run a DC IR drop simulation starting + from an EDB project. + + .. grid-item-card:: PCB AC analysis + :padding: 2 2 2 2 + :link: ac_q3d + :link-type: doc + + .. image:: _static/ac_q3d.png + :alt: AC Q3D + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a design in Q3D Extractor and run a simulation starting + from an EDB project. + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: ../../../aedt_general/modeler/circuit_schematic + :link-type: doc + + .. image:: ../../../aedt_general/modeler/_static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Circuit Netlist to Schematic + :padding: 2 2 2 2 + :link: ../../../aedt_general/modeler/netlist_to_schematic + :link-type: doc + + .. image:: ../../../aedt_general/modeler/_static/netlist.png + :alt: Netlist + :width: 250px + :height: 250px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Touchstone files + :padding: 2 2 2 2 + :link: ../../../aedt_general/report/touchstone_file + :link-type: doc + + .. image:: ../../../aedt_general/report/_static/touchstone_skitrf.png + :alt: Touchstone file + :width: 250px + :height: 200px + :align: center + + This example shows how to use objects in a Touchstone file without opening AEDT. + + + .. toctree:: + :hidden: + + power_integrity + dcir + dcir_q3d + ac_q3d + ../../../aedt_general/modeler/circuit_schematic + ../../../aedt_general/modeler/netlist_to_schematic + ../../../aedt_general/report/touchstone_file diff --git a/version/dev/_sources/examples/high_frequency/layout/power_integrity/power_integrity.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/power_integrity/power_integrity.ipynb.txt new file mode 100644 index 00000000..a5371b22 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/power_integrity/power_integrity.ipynb.txt @@ -0,0 +1,525 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "af6b86bd", + "metadata": {}, + "source": [ + "# Power integrity analysis\n", + "This example shows how to use the Ansys Electronics Database (EDB) for power integrity analysis. The\n", + "EDB is loaded into HFSS 3D Layout for analysis and postprocessing.\n", + "\n", + "- Set up EDB consists of these steps:\n", + "\n", + " - Assign S-parameter model to components.\n", + " - Create pin groups.\n", + " - Create ports.\n", + " - Create SIwave SYZ analysis.\n", + " - Create cutout.\n", + "\n", + "- Import EDB into HFSS 3D Layout:\n", + "\n", + " - Analyze.\n", + " - Plot ``$Z_{11}$``.\n", + "\n", + "Keywords: **HFSS 3D Layout**, **power integrity**." + ] + }, + { + "cell_type": "markdown", + "id": "6573b8e6", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Import the required packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f213789", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e57c559b", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.downloads import download_file" + ] + }, + { + "cell_type": "markdown", + "id": "29b66083", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc24bced", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "1a721bba", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e743cdca", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "680b12b5", + "metadata": {}, + "source": [ + "Download the example PCB data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1e4fdd5", + "metadata": {}, + "outputs": [], + "source": [ + "aedb = download_file(source=\"edb/ANSYS-HSD_V1.aedb\", destination=temp_folder.name)\n", + "download_file(\n", + " source=\"touchstone\",\n", + " name=\"GRM32_DC0V_25degC_series.s2p\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "82c4da1b", + "metadata": {}, + "source": [ + "## Create configuration file\n", + "This example uses a configuration file to set up the layout for analysis.\n", + "Initialize and create an empty dictionary to host all configurations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "199d180a", + "metadata": {}, + "outputs": [], + "source": [ + "cfg = dict()" + ] + }, + { + "cell_type": "markdown", + "id": "2f44d7ea", + "metadata": {}, + "source": [ + "Assigns S-parameter models to capacitors.\n", + "The first step is to use the \"general\" key to specify where the S-parameter files can be found." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a28b0b6", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"general\"] = {\"s_parameter_library\": os.path.join(temp_folder.name, \"touchstone\")}" + ] + }, + { + "cell_type": "markdown", + "id": "98c5fe6c", + "metadata": {}, + "source": [ + "## Assign model to capactitors\n", + "The model ``GRM32_DC0V_25degC_series.s2p`` is assigned to capacitors C3 and C4, which share the same component part number.\n", + "When \"apply_to_all\" is ``True``, all components having the part number \"CAPC3216X180X20ML20\" are assigned the S-parameter model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e1cdddc", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"s_parameters\"] = [\n", + " {\n", + " \"name\": \"GRM32_DC0V_25degC_series\",\n", + " \"component_definition\": \"CAPC0603X33X15LL03T05\",\n", + " \"file_path\": \"GRM32_DC0V_25degC_series.s2p\",\n", + " \"apply_to_all\": False,\n", + " \"components\": [\"C110\", \"C206\"],\n", + " \"reference_net\": \"GND\",\n", + " \"reference_net_per_component\": {\"C110\": \"GND\"},\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "8819f34b", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Create pin groups\n", + "Pins can be grouped explicitly by the pin name, or pin groups can be assigned by net name using the ''net'' key.\n", + "The following code combine the listed pins on component U2 into two pin groups using the ``net`` key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "015d2a4f", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"pin_groups\"] = [\n", + " {\n", + " \"name\": \"PIN_GROUP_1\",\n", + " \"reference_designator\": \"U1\",\n", + " \"pins\": [\"AD14\", \"AD15\", \"AD16\", \"AD17\"],\n", + " },\n", + " {\"name\": \"PIN_GROUP_2\", \"reference_designator\": \"U1\", \"net\": \"GND\"},\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "b7e32fdc", + "metadata": {}, + "source": [ + "## Create ports\n", + "Create a circuit port between the two pin groups just created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7418fde7", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"ports\"] = [\n", + " {\n", + " \"name\": \"port1\",\n", + " \"reference_designator\": \"U1\",\n", + " \"type\": \"circuit\",\n", + " \"positive_terminal\": {\"pin_group\": \"PIN_GROUP_1\"},\n", + " \"negative_terminal\": {\"pin_group\": \"PIN_GROUP_2\"},\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "d3d7918a", + "metadata": {}, + "source": [ + "## Create SIwave SYZ analysis setup\n", + "Both SIwave and HFSS can be used to run an analysis in the 3D Layout user interface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "766474f5", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"setups\"] = [\n", + " {\n", + " \"name\": \"siwave_syz\",\n", + " \"type\": \"siwave_syz\",\n", + " \"pi_slider_position\": 1,\n", + " \"freq_sweep\": [\n", + " {\n", + " \"name\": \"Sweep1\",\n", + " \"type\": \"Interpolation\",\n", + " \"frequencies\": [\n", + " {\n", + " \"distribution\": \"log scale\",\n", + " \"start\": 1e6,\n", + " \"stop\": 1e9,\n", + " \"samples\": 20,\n", + " }\n", + " ],\n", + " }\n", + " ],\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "84cb4f42", + "metadata": {}, + "source": [ + "## Define cutout\n", + "Define the region of the PCB to be cut out for analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9aad362a", + "metadata": {}, + "outputs": [], + "source": [ + "cfg[\"operations\"] = {\n", + " \"cutout\": {\n", + " \"signal_list\": [\"1V0\"],\n", + " \"reference_list\": [\"GND\"],\n", + " \"extent_type\": \"ConvexHull\",\n", + " \"expansion_size\": 0.002,\n", + " \"use_round_corner\": False,\n", + " \"output_aedb_path\": \"\",\n", + " \"open_cutout_at_end\": True,\n", + " \"use_pyaedt_cutout\": True,\n", + " \"number_of_threads\": 4,\n", + " \"use_pyaedt_extent_computing\": True,\n", + " \"extent_defeature\": 0,\n", + " \"remove_single_pin_components\": False,\n", + " \"custom_extent\": \"\",\n", + " \"custom_extent_units\": \"mm\",\n", + " \"include_partial_instances\": False,\n", + " \"keep_voids\": True,\n", + " \"check_terminals\": False,\n", + " \"include_pingroups\": False,\n", + " \"expansion_factor\": 0,\n", + " \"maximum_iterations\": 10,\n", + " \"preserve_components_with_model\": False,\n", + " \"simple_pad_check\": True,\n", + " \"keep_lines_as_path\": False,\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "f9d9f785", + "metadata": {}, + "source": [ + "## Save configuration\n", + "\n", + "Save the configuration file to a JSON file and apply it to layout data using the EDB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ddcf804", + "metadata": {}, + "outputs": [], + "source": [ + "pi_json = os.path.join(temp_folder.name, \"pi.json\")\n", + "with open(pi_json, \"w\") as f:\n", + " json.dump(cfg, f, indent=4, ensure_ascii=False)" + ] + }, + { + "cell_type": "markdown", + "id": "5ac9a71d", + "metadata": {}, + "source": [ + "## Load configuration into EDB" + ] + }, + { + "cell_type": "markdown", + "id": "362bd4e2", + "metadata": {}, + "source": [ + "Load the configuration into EDB from the JSON file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0728a70", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp = ansys.aedt.core.Edb(aedb, edbversion=AEDT_VERSION)\n", + "edbapp.configuration.load(config_file=pi_json)\n", + "edbapp.configuration.run()\n", + "edbapp.save()\n", + "edbapp.close()" + ] + }, + { + "cell_type": "markdown", + "id": "1667b0f4", + "metadata": {}, + "source": [ + "The configured EDB file is saved in the temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "761b11a7", + "metadata": {}, + "outputs": [], + "source": [ + "print(temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "e280f802", + "metadata": {}, + "source": [ + "## Analyze in HFSS 3D Layout" + ] + }, + { + "cell_type": "markdown", + "id": "35b3b89d", + "metadata": {}, + "source": [ + "### Load EDB into HFSS 3D Layout" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e58f50bf", + "metadata": {}, + "outputs": [], + "source": [ + "h3d = ansys.aedt.core.Hfss3dLayout(\n", + " aedb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d1bc253f", + "metadata": {}, + "source": [ + "### Analyze" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "669dc99a", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "fffa74bc", + "metadata": {}, + "source": [ + "### Plot impedance" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07299b62", + "metadata": {}, + "outputs": [], + "source": [ + "solutions = h3d.post.get_solution_data(expressions=\"Z(port1,port1)\")\n", + "solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "6941a337", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab81d5f1", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.save_project()\n", + "h3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "598410b8", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd962c0d", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/ami.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/ami.ipynb.txt new file mode 100644 index 00000000..bcb3f128 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/ami.ipynb.txt @@ -0,0 +1,596 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7036c6cc", + "metadata": {}, + "source": [ + "# AMI Postprocessing\n", + "\n", + "This example demonstrates advanced postprocessing of AMI simulations.\n", + "\n", + "Keywords: **Circuit**, **AMI**." + ] + }, + { + "cell_type": "markdown", + "id": "1c04463a", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports.\n", + "\n", + "> **Note:** [Numpy](https://numpy.org/)\n", + "> and [Matplotlib](https://matplotlib.org/) are required to run this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbc76c3f", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n" + ] + }, + { + "cell_type": "markdown", + "id": "7630653d", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bab4ba39", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "0fe75c83", + "metadata": {}, + "source": [ + "## Create temporary directory and download example files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93859951", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "5c8f96b9", + "metadata": {}, + "source": [ + "## Download example data\n", + "\n", + "The ``download_file()`` method retrieves example\n", + "data from the PyAnsys\n", + "[example-data](https://github.com/ansys/example-data/tree/master/pyaedt) repository.\n", + "\n", + "- The fist argument is the folder name where\n", + " the example files are located in the GitHub repository.\n", + "- The 2nd argument is the file to retrieve.\n", + "- The 3rd argument is the destination folder.\n", + "\n", + "Files are placed in the destination folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5136e296", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " \"ami\", name=\"ami_usb.aedtz\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6d9169c1", + "metadata": {}, + "source": [ + "## Launch AEDT with Circuit and enable Pandas as the output format\n", + "\n", + "All outputs obtained with the `get_solution_data()` method are in the\n", + "[Pandas](https://pandas.pydata.org/docs/user_guide/index.html) format.\n", + "Launch AEDT with Circuit. The `ansys.aedt.core.Desktop` class initializes AEDT\n", + "and starts the specified version in the specified mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a04bd56", + "metadata": {}, + "outputs": [], + "source": [ + "ansys.aedt.core.settings.enable_pandas_output = True\n", + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(project_path),\n", + " non_graphical=NG_MODE,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6960dea4", + "metadata": {}, + "source": [ + "## Solve AMI setup\n", + "\n", + "Solve the transient setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4a0a028", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "4450e4ff", + "metadata": {}, + "source": [ + "## Get AMI report\n", + "\n", + "Get AMI report data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24a663a8", + "metadata": {}, + "outputs": [], + "source": [ + "plot_name = \"WaveAfterProbe\"\n", + "circuit.solution_type = \"NexximAMI\"\n", + "original_data = circuit.post.get_solution_data(\n", + " expressions=plot_name,\n", + " setup_sweep_name=\"AMIAnalysis\",\n", + " domain=\"Time\",\n", + " variations=circuit.available_variations.nominal,\n", + ")\n", + "original_data_value = original_data.full_matrix_real_imag[0]\n", + "original_data_sweep = original_data.primary_sweep_values\n", + "print(original_data_value)" + ] + }, + { + "cell_type": "markdown", + "id": "b0bc4cd6", + "metadata": {}, + "source": [ + "## Plot data\n", + "\n", + "Create a plot based on solution data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "559443ac", + "metadata": {}, + "outputs": [], + "source": [ + "fig = original_data.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "c32a05be", + "metadata": {}, + "source": [ + "## Extract wave form\n", + "\n", + "Use the ``WaveAfterProbe`` plot type to extract the\n", + "waveform using an AMI receiver clock probe.\n", + "The signal is extracted at a specific clock\n", + "flank with additional half unit interval." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59bd1d00", + "metadata": {}, + "outputs": [], + "source": [ + "probe_name = \"b_input_43\"\n", + "source_name = \"b_output4_42\"\n", + "plot_type = \"WaveAfterProbe\"\n", + "setup_name = \"AMIAnalysis\"\n", + "ignore_bits = 100\n", + "unit_interval = 0.1e-9\n", + "sample_waveform = circuit.post.sample_ami_waveform(\n", + " setup=setup_name,\n", + " probe=probe_name,\n", + " source=source_name,\n", + " variation_list_w_value=circuit.available_variations.nominal,\n", + " unit_interval=unit_interval,\n", + " ignore_bits=ignore_bits,\n", + " plot_type=plot_type,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e1f97df4", + "metadata": {}, + "source": [ + "## Plot waveform and samples\n", + "\n", + "Create the plot from a start time to stop time in seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7d48c68", + "metadata": {}, + "outputs": [], + "source": [ + "tstop = 55e-9\n", + "tstart = 50e-9\n", + "scale_time = ansys.aedt.core.constants.unit_converter(\n", + " 1,\n", + " unit_system=\"Time\",\n", + " input_units=\"s\",\n", + " output_units=original_data.units_sweeps[\"Time\"],\n", + ")\n", + "scale_data = ansys.aedt.core.constants.unit_converter(\n", + " 1,\n", + " unit_system=\"Voltage\",\n", + " input_units=\"V\",\n", + " output_units=original_data.units_data[plot_name],\n", + ")\n", + "\n", + "tstop_ns = scale_time * tstop\n", + "tstart_ns = scale_time * tstart\n", + "\n", + "for time_value in original_data_value[plot_name].index:\n", + " if tstart_ns <= time_value[0]:\n", + " start_index_original_data = time_value[0]\n", + " break\n", + "for time_value in original_data_value[plot_name][start_index_original_data:].index:\n", + " if time_value[0] >= tstop_ns:\n", + " stop_index_original_data = time_value[0]\n", + " break\n", + "for time_value in sample_waveform[0].index:\n", + " if tstart <= time_value:\n", + " sample_index = sample_waveform[0].index == time_value\n", + " start_index_waveform = sample_index.tolist().index(True)\n", + " break\n", + "for time_value in sample_waveform[0].index:\n", + " if time_value >= tstop:\n", + " sample_index = sample_waveform[0].index == time_value\n", + " stop_index_waveform = sample_index.tolist().index(True)\n", + " break\n", + "\n", + "original_data_zoom = original_data_value[\n", + " start_index_original_data:stop_index_original_data\n", + "]\n", + "sampled_data_zoom = (\n", + " sample_waveform[0].values[start_index_waveform:stop_index_waveform] * scale_data\n", + ")\n", + "sampled_time_zoom = (\n", + " sample_waveform[0].index[start_index_waveform:stop_index_waveform] * scale_time\n", + ")\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(sampled_time_zoom, sampled_data_zoom, \"r*\")\n", + "ax.plot(\n", + " np.array(list(original_data_zoom.index.values)),\n", + " original_data_zoom.values,\n", + " color=\"blue\",\n", + ")\n", + "ax.set_title(\"WaveAfterProbe\")\n", + "ax.set_xlabel(original_data.units_sweeps[\"Time\"])\n", + "ax.set_ylabel(original_data.units_data[plot_name])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "dc71ec88", + "metadata": {}, + "source": [ + "## Plot slicer scatter\n", + "\n", + "Create the plot from a start time to stop time in seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92d22c83", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax2 = plt.subplots()\n", + "ax2.plot(sample_waveform[0].index, sample_waveform[0].values, \"r*\")\n", + "ax2.set_title(\"Slicer Scatter: WaveAfterProbe\")\n", + "ax2.set_xlabel(\"s\")\n", + "ax2.set_ylabel(\"V\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a3608c07", + "metadata": {}, + "source": [ + "## Plot scatter histogram\n", + "\n", + "Create the plot from a start time to stop time in seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c56f5a1", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax4 = plt.subplots()\n", + "ax4.set_title(\"Slicer Histogram: WaveAfterProbe\")\n", + "ax4.hist(sample_waveform[0].values, orientation=\"horizontal\")\n", + "ax4.set_ylabel(\"V\")\n", + "ax4.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e036eb59", + "metadata": {}, + "source": [ + "## Get transient report data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ca5d352", + "metadata": {}, + "outputs": [], + "source": [ + "plot_name = \"V(b_input_43.int_ami_rx.eye_probe.out)\"\n", + "circuit.solution_type = \"NexximTransient\"\n", + "original_data = circuit.post.get_solution_data(\n", + " expressions=plot_name,\n", + " setup_sweep_name=\"NexximTransient\",\n", + " domain=\"Time\",\n", + " variations=circuit.available_variations.nominal,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "01701c2c", + "metadata": {}, + "source": [ + "## Extract sample waveform\n", + "\n", + "Extract a waveform at a specific clock time plus a half unit interval." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b882eeb", + "metadata": {}, + "outputs": [], + "source": [ + "original_data.enable_pandas_output = False\n", + "original_data_value = original_data.data_real()\n", + "original_data_sweep = original_data.primary_sweep_values\n", + "waveform_unit = original_data.units_data[plot_name]\n", + "waveform_sweep_unit = original_data.units_sweeps[\"Time\"]\n", + "tics = np.arange(20e-9, 100e-9, 1e-10, dtype=float)\n", + "\n", + "sample_waveform = circuit.post.sample_waveform(\n", + " waveform_data=original_data_value,\n", + " waveform_sweep=original_data_sweep,\n", + " waveform_unit=waveform_unit,\n", + " waveform_sweep_unit=waveform_sweep_unit,\n", + " unit_interval=unit_interval,\n", + " clock_tics=tics,\n", + " pandas_enabled=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9e3a0bfd", + "metadata": {}, + "source": [ + "## Plot waveform\n", + "\n", + "Create the plot from a start time to stop time in seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "527ac7f9", + "metadata": {}, + "outputs": [], + "source": [ + "tstop = 40.0e-9\n", + "tstart = 25.0e-9\n", + "scale_time = ansys.aedt.core.constants.unit_converter(\n", + " 1, unit_system=\"Time\", input_units=\"s\", output_units=waveform_sweep_unit\n", + ")\n", + "scale_data = ansys.aedt.core.constants.unit_converter(\n", + " 1, unit_system=\"Voltage\", input_units=\"V\", output_units=waveform_unit\n", + ")\n", + "\n", + "tstop_ns = scale_time * tstop\n", + "tstart_ns = scale_time * tstart\n", + "\n", + "for time_value in original_data_sweep:\n", + " if tstart_ns <= time_value:\n", + " start_index_original_data = original_data_sweep.index(time_value)\n", + " break\n", + "for time_value in original_data_sweep[start_index_original_data:]:\n", + " if time_value >= tstop_ns:\n", + " stop_index_original_data = original_data_sweep.index(time_value)\n", + " break\n", + "cont = 0\n", + "for frame in sample_waveform:\n", + " if tstart <= frame[0]:\n", + " start_index_waveform = cont\n", + " break\n", + " cont += 1\n", + "for frame in sample_waveform[start_index_waveform:]:\n", + " if frame[0] >= tstop:\n", + " stop_index_waveform = cont\n", + " break\n", + " cont += 1\n", + "\n", + "original_data_zoom = original_data_value[\n", + " start_index_original_data:stop_index_original_data\n", + "]\n", + "original_sweep_zoom = original_data_sweep[\n", + " start_index_original_data:stop_index_original_data\n", + "]\n", + "original_data_zoom_array = np.array(\n", + " list(map(list, zip(original_sweep_zoom, original_data_zoom)))\n", + ")\n", + "original_data_zoom_array[:, 0] *= 1\n", + "sampled_data_zoom_array = np.array(\n", + " sample_waveform[start_index_waveform:stop_index_waveform]\n", + ")\n", + "sampled_data_zoom_array[:, 0] *= scale_time\n", + "sampled_data_zoom_array[:, 1] *= scale_data\n", + "\n", + "fig, ax = plt.subplots()\n", + "ax.plot(sampled_data_zoom_array[:, 0], sampled_data_zoom_array[:, 1], \"r*\")\n", + "ax.plot(original_sweep_zoom, original_data_zoom_array[:, 1], color=\"blue\")\n", + "ax.set_title(plot_name)\n", + "ax.set_xlabel(waveform_sweep_unit)\n", + "ax.set_ylabel(waveform_unit)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "bada659e", + "metadata": {}, + "source": [ + "## Plot slicer scatter\n", + "\n", + "Create the plot from a start time to stop time in seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c506a02", + "metadata": {}, + "outputs": [], + "source": [ + "sample_waveform_array = np.array(sample_waveform)\n", + "fig, ax2 = plt.subplots()\n", + "ax2.plot(sample_waveform_array[:, 0], sample_waveform_array[:, 1], \"r*\")\n", + "ax2.set_title(\"Slicer Scatter: \" + plot_name)\n", + "ax2.set_xlabel(\"s\")\n", + "ax2.set_ylabel(\"V\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "5f71751e", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e647300b", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "0f550a53", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54ff0cb2", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/circuit_transient.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/circuit_transient.ipynb.txt new file mode 100644 index 00000000..efbc8504 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/circuit_transient.ipynb.txt @@ -0,0 +1,453 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5240fdbe", + "metadata": {}, + "source": [ + "# Circuit transient analysis and eye diagram\n", + "\n", + "This example shows how to create a circuit design,\n", + "run a Nexxim time-domain simulation, and create an eye diagram.\n", + "\n", + "Keywords: **Circuit**, **transient**, **eye diagram**." + ] + }, + { + "cell_type": "markdown", + "id": "c77998fd", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6ca0c59", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n" + ] + }, + { + "cell_type": "markdown", + "id": "eb4b75a2", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9973f03b", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "5f303671", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e8a1f6b", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "381bfe2f", + "metadata": {}, + "source": [ + "## Launch AEDT with Circuit\n", + "\n", + "Launch AEDT in graphical mode with the Circuit schematic editor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8de35fd3", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = ansys.aedt.core.Circuit(\n", + " project=os.path.join(temp_folder.name, \"CktTransient\"),\n", + " design=\"Circuit Examples\",\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9cfbe97b", + "metadata": {}, + "source": [ + "## Place IBIS buffer\n", + "\n", + "Read an IBIS file and place a buffer in the schematic editor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed23094b", + "metadata": {}, + "outputs": [], + "source": [ + "ibis = circuit.get_ibis_model_from_file(\n", + " os.path.join(circuit.desktop_install_dir, \"buflib\", \"IBIS\", \"u26a_800.ibs\")\n", + ")\n", + "ibs = ibis.buffers[\"DQ_u26a_800\"].insert(0, 0)" + ] + }, + { + "cell_type": "markdown", + "id": "dc87320d", + "metadata": {}, + "source": [ + "## Place ideal transmission line\n", + "\n", + "Place an ideal transmission line in the schematic and parametrize it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7418b17a", + "metadata": {}, + "outputs": [], + "source": [ + "tr1 = circuit.modeler.components.components_catalog[\"Ideal Distributed:TRLK_NX\"].place(\n", + " \"tr1\"\n", + ")\n", + "tr1.parameters[\"P\"] = \"50mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "1d4a2471", + "metadata": {}, + "source": [ + "## Place components\n", + "\n", + "Create a resistor and ground in the schematic." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6527c89", + "metadata": {}, + "outputs": [], + "source": [ + "res = circuit.modeler.components.create_resistor(name=\"R1\", value=\"1Meg\")\n", + "gnd1 = circuit.modeler.components.create_gnd()" + ] + }, + { + "cell_type": "markdown", + "id": "84329efc", + "metadata": {}, + "source": [ + "## Connect componennts\n", + "\n", + "Connect the components in the schematic." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e38151d", + "metadata": {}, + "outputs": [], + "source": [ + "tr1.pins[0].connect_to_component(ibs.pins[0])\n", + "tr1.pins[1].connect_to_component(res.pins[0])\n", + "res.pins[1].connect_to_component(gnd1.pins[0])" + ] + }, + { + "cell_type": "markdown", + "id": "1b4c91b4", + "metadata": {}, + "source": [ + "## Place a probe\n", + "\n", + "Place a voltage probe and rename it to ``Vout``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c558e77", + "metadata": {}, + "outputs": [], + "source": [ + "pr1 = circuit.modeler.components.components_catalog[\"Probes:VPROBE\"].place(\"vout\")\n", + "pr1.parameters[\"Name\"] = \"Vout\"\n", + "pr1.pins[0].connect_to_component(res.pins[0])\n", + "pr2 = circuit.modeler.components.components_catalog[\"Probes:VPROBE\"].place(\"Vin\")\n", + "pr2.parameters[\"Name\"] = \"Vin\"\n", + "pr2.pins[0].connect_to_component(ibs.pins[0])" + ] + }, + { + "cell_type": "markdown", + "id": "b0915269", + "metadata": {}, + "source": [ + "## Analyze\n", + "\n", + "Create a transient analysis setup and analyze it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41bb393d", + "metadata": {}, + "outputs": [], + "source": [ + "trans_setup = circuit.create_setup(name=\"TransientRun\", setup_type=\"NexximTransient\")\n", + "trans_setup.props[\"TransientData\"] = [\"0.01ns\", \"200ns\"]\n", + "circuit.analyze_setup(\"TransientRun\")" + ] + }, + { + "cell_type": "markdown", + "id": "a3f62424", + "metadata": {}, + "source": [ + "## Create report\n", + "\n", + "Create a report using the ``get_solution_data()`` method. This\n", + "method allows you to view and postprocess results using Python packages.\n", + "The ``solutions.plot()`` method uses\n", + "[Matplotlib](https://matplotlib.org/)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44a8d1f0", + "metadata": {}, + "outputs": [], + "source": [ + "report = circuit.post.create_report(\"V(Vout)\", domain=\"Time\")\n", + "if not NG_MODE:\n", + " report.add_cartesian_y_marker(0)\n", + "solutions = circuit.post.get_solution_data(domain=\"Time\")\n", + "solutions.plot(\"V(Vout)\")" + ] + }, + { + "cell_type": "markdown", + "id": "d141f142", + "metadata": {}, + "source": [ + "## Visualize results\n", + "\n", + "Create a report inside AEDT using the ``new_report`` object. This object is\n", + "fully customizable and usable with most of the reports available in AEDT.\n", + "The standard report is the main one used in Circuit and Twin Builder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e16695fd", + "metadata": {}, + "outputs": [], + "source": [ + "new_report = circuit.post.reports_by_category.standard(\"V(Vout)\")\n", + "new_report.domain = \"Time\"\n", + "new_report.create()\n", + "if not NG_MODE:\n", + " new_report.add_limit_line_from_points([60, 80], [1, 1], \"ns\", \"V\")\n", + " vout = new_report.traces[0]\n", + " vout.set_trace_properties(\n", + " style=vout.LINESTYLE.Dot,\n", + " width=2,\n", + " trace_type=vout.TRACETYPE.Continuous,\n", + " color=(0, 0, 255),\n", + " )\n", + " vout.set_symbol_properties(\n", + " style=vout.SYMBOLSTYLE.Circle, fill=True, color=(255, 255, 0)\n", + " )\n", + " ll = new_report.limit_lines[0]\n", + " ll.set_line_properties(\n", + " style=ll.LINESTYLE.Solid,\n", + " width=4,\n", + " hatch_above=True,\n", + " violation_emphasis=True,\n", + " hatch_pixels=2,\n", + " color=(0, 0, 255),\n", + " )\n", + "new_report.time_start = \"20ns\"\n", + "new_report.time_stop = \"100ns\"\n", + "new_report.create()\n", + "sol = new_report.get_solution_data()\n", + "sol.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "34576ca2", + "metadata": {}, + "source": [ + "## Create eye diagram in AEDT\n", + "\n", + "Create an eye diagram inside AEDT using the ``new_eye`` object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f2cdbe1", + "metadata": {}, + "outputs": [], + "source": [ + "new_eye = circuit.post.reports_by_category.eye_diagram(\"V(Vout)\")\n", + "new_eye.unit_interval = \"1e-9s\"\n", + "new_eye.time_stop = \"100ns\"\n", + "new_eye.create()" + ] + }, + { + "cell_type": "markdown", + "id": "cc03b78b", + "metadata": {}, + "source": [ + "## Create eye diagram in Matplotlib\n", + "\n", + "Create the same eye diagram outside AEDT using Matplotlib and the\n", + "``get_solution_data()`` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f92ddb9", + "metadata": {}, + "outputs": [], + "source": [ + "unit_interval = 1\n", + "offset = 0.25\n", + "tstop = 200\n", + "tstart = 0\n", + "t_steps = []\n", + "i = tstart + offset\n", + "while i < tstop:\n", + " i += 2 * unit_interval\n", + " t_steps.append(i)\n", + "\n", + "t = [\n", + " [i for i in solutions.intrinsics[\"Time\"] if k - 2 * unit_interval < i <= k]\n", + " for k in t_steps\n", + "]\n", + "ys = [\n", + " [\n", + " i / 1000\n", + " for i, j in zip(solutions.data_real(), solutions.intrinsics[\"Time\"])\n", + " if k - 2 * unit_interval < j <= k\n", + " ]\n", + " for k in t_steps\n", + "]\n", + "fig, ax = plt.subplots(sharex=True)\n", + "cells = np.array([])\n", + "cellsv = np.array([])\n", + "for a, b in zip(t, ys):\n", + " an = np.array(a)\n", + " an = an - an.mean()\n", + " bn = np.array(b)\n", + " cells = np.append(cells, an)\n", + " cellsv = np.append(cellsv, bn)\n", + "plt.plot(cells.T, cellsv.T, zorder=0)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "fd2a94e1", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94ef2c69", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "7b9276f8", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "807ea790", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/com_analysis.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/com_analysis.ipynb.txt new file mode 100644 index 00000000..19e55eed --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/com_analysis.ipynb.txt @@ -0,0 +1,335 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9b575b14", + "metadata": {}, + "source": [ + "# Channel Operating Margin (COM)\n", + "This example shows how to use PyAEDT for COM analysis.\n", + "These standards are supported:\n", + "\n", + "- 50GAUI_1_C2C\n", + "- 100GAUI_2_C2C\n", + "- 200GAUI_4\n", + "- 400GAUI_8\n", + "- 100GBASE_KR4\n", + "- 100GBASE_KP4" + ] + }, + { + "cell_type": "markdown", + "id": "7c799754", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "5024bfe7", + "metadata": {}, + "source": [ + "## What is COM?\n", + "\n", + "- COM was developed as part of IEEE 802.3bj, 100GBASE Ethernet.\n", + "- COM is a figure of merit for an S-parameter representing a high-speed SerDes channel.\n", + "- COM is the ratio between eye height and noise." + ] + }, + { + "cell_type": "markdown", + "id": "327b5b9e", + "metadata": {}, + "source": [ + "```math\n", + "COM = 20 * log10 (A_signal / A_noise)\n", + "```\n", + "\n", + "Keywords: **COM**, **signal integrity**, **virtual compliance**." + ] + }, + { + "cell_type": "markdown", + "id": "0056ec1c", + "metadata": {}, + "source": [ + "## Perform imports\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97b6acf3", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad209979", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core.visualization.post.spisim import SpiSim\n", + "from ansys.aedt.core.visualization.post.spisim_com_configuration_files import \\\n", + " com_parameters\n", + "from pyedb.misc.downloads import download_file" + ] + }, + { + "cell_type": "markdown", + "id": "8ff30b3a", + "metadata": {}, + "source": [ + "## Create temporary directory and download example files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "428ff2dd", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "\n", + "thru = download_file(\n", + " directory=\"com_analysis\",\n", + " filename=\"SerDes_Demo_02_Thru.s4p\",\n", + " destination=temp_folder.name,\n", + ")\n", + "fext_2_9 = download_file(\n", + " directory=\"com_analysis\",\n", + " filename=\"FCI_CC_Long_Link_Pair_2_to_Pair_9_FEXT.s4p\",\n", + " destination=temp_folder.name,\n", + ")\n", + "fext_5_9 = download_file(\n", + " directory=\"com_analysis\",\n", + " filename=\"FCI_CC_Long_Link_Pair_5_to_Pair_9_FEXT.s4p\",\n", + " destination=temp_folder.name,\n", + ")\n", + "next_11_9 = download_file(\n", + " directory=\"com_analysis\",\n", + " filename=\"FCI_CC_Long_Link_Pair_11_to_Pair_9_NEXT.s4p\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d65a150b", + "metadata": {}, + "source": [ + "## Run COM analysis\n", + "PyAEDT calls SPISim for COM analysis. For supported standardes, see the PyAEDT documentation." + ] + }, + { + "cell_type": "markdown", + "id": "b45f526a", + "metadata": {}, + "source": [ + "Set ``port_order=\"EvenOdd\"`` when the S-parameter has this port order:\n", + "\n", + "1 - 2\n", + "\n", + "3 - 4\n", + "\n", + "Set ``port_order=\"Incremental\"`` when the S-parameter has this port order:\n", + "\n", + "1 - 3\n", + "\n", + "2 - 4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78a3e391", + "metadata": {}, + "outputs": [], + "source": [ + "spi_sim = SpiSim(thru)\n", + "com_results = spi_sim.compute_com(\n", + " standard=1, # 50GAUI-1-C2C\n", + " port_order=\"EvenOdd\",\n", + " fext_s4p=[fext_5_9, fext_5_9],\n", + " next_s4p=next_11_9,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "81f7a283", + "metadata": {}, + "source": [ + "## Print COM values\n", + "There are two COM values reported by the definition of the standard:\n", + "\n", + "- Case 0: COM value in dB when big package is used.\n", + "- Case 1: COM value in dB when small package is used." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c19aac3", + "metadata": {}, + "outputs": [], + "source": [ + "print(*com_results)" + ] + }, + { + "cell_type": "markdown", + "id": "8fd8bf41", + "metadata": {}, + "source": [ + "## View COM report\n", + "A complete COM report is generated in the temporary folder in HTML format." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9687bc94", + "metadata": {}, + "outputs": [], + "source": [ + "print(temp_folder.name)" + ] + }, + { + "cell_type": "markdown", + "id": "5b9d350d", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "01f49a26", + "metadata": {}, + "source": [ + "## Run COM analysis on custom configuration file" + ] + }, + { + "cell_type": "markdown", + "id": "73decab0", + "metadata": {}, + "source": [ + "### Export template configuration file in JSON format" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ccf5d7b", + "metadata": {}, + "outputs": [], + "source": [ + "custom_json = os.path.join(temp_folder.name, \"custom.json\")\n", + "spi_sim.export_com_configure_file(custom_json, standard=1)" + ] + }, + { + "cell_type": "markdown", + "id": "8e7b5cb0", + "metadata": {}, + "source": [ + "Modify the custom JSON file as needed." + ] + }, + { + "cell_type": "markdown", + "id": "3af8eeeb", + "metadata": {}, + "source": [ + "### Import configuration file and run" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e0809da", + "metadata": {}, + "outputs": [], + "source": [ + "com_results = spi_sim.compute_com(\n", + " standard=0, # Custom\n", + " config_file=custom_json,\n", + " port_order=\"EvenOdd\",\n", + " fext_s4p=[fext_5_9, fext_5_9],\n", + " next_s4p=next_11_9,\n", + ")\n", + "print(*com_results)" + ] + }, + { + "cell_type": "markdown", + "id": "67e002b6", + "metadata": {}, + "source": [ + "## Export SPISim supported configuration file\n", + "You can use the exported configuration file in the SPISim GUI." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6f85125", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "com_param = com_parameters.COMParametersVer3p4()\n", + "com_param.load(custom_json)\n", + "custom_cfg = os.path.join(temp_folder.name, \"custom.cfg\")\n", + "com_param.export_spisim_cfg(custom_cfg)" + ] + }, + { + "cell_type": "markdown", + "id": "5cb816dc", + "metadata": {}, + "source": [ + "PyAEDT also supports the SPISim configuration file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66dca65e", + "metadata": {}, + "outputs": [], + "source": [ + "com_results = spi_sim.compute_com(\n", + " standard=0, config_file=custom_cfg, port_order=\"EvenOdd\"\n", + ") # Custom\n", + "print(*com_results)" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/index.rst.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/index.rst.txt new file mode 100644 index 00000000..0f782871 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/index.rst.txt @@ -0,0 +1,166 @@ +Signal integrity +~~~~~~~~~~~~~~~~ + +These examples use PyAEDT to show signal integrity examples. + +.. grid:: 2 + + .. grid-item-card:: Channel Operating Margin (COM) + :padding: 2 2 2 2 + :link: com_analysis + :link-type: doc + + .. image:: _static/com_eye.png + :alt: COM + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT for COM analysis. + + .. grid-item-card:: Pre-layout signal integrity + :padding: 2 2 2 2 + :link: pre_layout + :link-type: doc + + .. image:: _static/pre_layout_sma_connector_on_pcb.png + :alt: Pre layout connector + :width: 250px + :height: 200px + :align: center + + This example shows how to create a parameterized layout design and load the layout into HFSS 3D Layout + for analysis and postprocessing. + + .. grid-item-card:: Pre-layout Parameterized PCB + :padding: 2 2 2 2 + :link: pre_layout_parametrized + :link-type: doc + + .. image:: _static/pre_layout_parameterized_pcb.png + :alt: Pre layout parametrized + :width: 250px + :height: 200px + :align: center + + This example shows how to use the EDB interface along with HFSS 3D Layout to create and solve a parameterized layout. + + .. grid-item-card:: AMI Postprocessing + :padding: 2 2 2 2 + :link: ami + :link-type: doc + + .. image:: _static/ami.png + :alt: AMI + :width: 250px + :height: 200px + :align: center + + This example demonstrates advanced postprocessing of AMI simulations. + + .. grid-item-card:: Multi-zone simulation with SIwave + :padding: 2 2 2 2 + :link: multizone + :link-type: doc + + .. image:: _static/multizone.png + :alt: Multizone + :width: 250px + :height: 200px + :align: center + + This example shows how to simulate multiple zones with SIwave. + + .. grid-item-card:: Circuit transient analysis and eye diagram + :padding: 2 2 2 2 + :link: circuit_transient + :link-type: doc + + .. image:: _static/circuit_transient.png + :alt: Circuit transient + :width: 250px + :height: 200px + :align: center + + This example shows how to create a circuit design, run a Nexxim time-domain simulation, and create an eye diagram. + + .. grid-item-card:: Circuit schematic creation and analysis + :padding: 2 2 2 2 + :link: ../../../aedt_general/modeler/circuit_schematic + :link-type: doc + + .. image:: ../../../aedt_general/modeler/_static/circuit.png + :alt: Circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Circuit Netlist to Schematic + :padding: 2 2 2 2 + :link: ../../../aedt_general/modeler/netlist_to_schematic + :link-type: doc + + .. image:: ../../../aedt_general/modeler/_static/netlist.png + :alt: Netlist + :width: 250px + :height: 250px + :align: center + + This example shows how to build a circuit schematic and run a transient circuit simulation. + + .. grid-item-card:: Schematic subcircuit management + :padding: 2 2 2 2 + :link: ../../emc/subcircuit + :link-type: doc + + .. image:: ../../emc/_static/subcircuit.png + :alt: Cable + :width: 250px + :height: 200px + :align: center + + This example shows how to add a subcircuit to a circuit design. + It changes the focus within the hierarchy between the child subcircuit and the parent design. + + .. grid-item-card:: Touchstone files + :padding: 2 2 2 2 + :link: ../../../aedt_general/report/touchstone_file + :link-type: doc + + .. image:: ../../../aedt_general/report/_static/touchstone_skitrf.png + :alt: Touchstone file + :width: 250px + :height: 200px + :align: center + + This example shows how to use objects in a Touchstone file without opening AEDT. + + .. grid-item-card:: PCIE virtual compliance + :padding: 2 2 2 2 + :link: ../../../aedt_general/report/virtual_compliance + :link-type: doc + + .. image:: ../../../aedt_general/report/_static/virtual_compliance_eye.png + :alt: Virtual compliance + :width: 250px + :height: 200px + :align: center + + This example shows how to generate a compliance report in PyAEDT using the VirtualCompliance class. + + .. toctree:: + :hidden: + + com_analysis + pre_layout + pre_layout_parametrized + ami + multizone + circuit_transient + ../../../aedt_general/modeler/circuit_schematic + ../../../aedt_general/modeler/netlist_to_schematic + ../../emc/subcircuit + ../../../aedt_general/report/touchstone_file + ../../../aedt_general/report/virtual_compliance diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/multizone.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/multizone.ipynb.txt new file mode 100644 index 00000000..6a48aa17 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/multizone.ipynb.txt @@ -0,0 +1,402 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7b5ef422", + "metadata": {}, + "source": [ + "# Multi-zone simulation with SIwave\n", + "\n", + "This example shows how to simulate multiple zones with SIwave.\n", + "\n", + "Keywords: **Circuit**, **multi-zone**." + ] + }, + { + "cell_type": "markdown", + "id": "e9136cdf", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports, which includes importing a section." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3ab767c", + "metadata": {}, + "outputs": [], + "source": [ + "import os.path\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n", + "from ansys.aedt.core import Circuit, Edb\n" + ] + }, + { + "cell_type": "markdown", + "id": "7f9d103d", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5cadc6f", + "metadata": {}, + "outputs": [], + "source": [ + "EDB_VERSION = \"2024.2\"" + ] + }, + { + "cell_type": "markdown", + "id": "3f482bde", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58d31efa", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "19dfce88", + "metadata": {}, + "source": [ + "## Download EDB folder" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91faa711", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "edb_file = ansys.aedt.core.downloads.download_file(\n", + " directory=\"edb/siwave_multi_zones.aedb\", destination=temp_folder.name\n", + ")\n", + "work_folder = os.path.join(temp_folder.name, \"work\")\n", + "aedt_file = os.path.splitext(edb_file)[0] + \".aedt\"\n", + "circuit_project_file = os.path.join(temp_folder.name, \"multizone_clipped_circuit.aedt\")\n", + "print(edb_file)" + ] + }, + { + "cell_type": "markdown", + "id": "5701a056", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Set AEDT version" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa0b5efd", + "metadata": {}, + "outputs": [], + "source": [ + "edb_version = EDB_VERSION" + ] + }, + { + "cell_type": "markdown", + "id": "6f64ed3d", + "metadata": {}, + "source": [ + "## Define ground net\n", + "\n", + "Define the common reference net used across all subdesigns, which is mandatory for this workflow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb316850", + "metadata": {}, + "outputs": [], + "source": [ + "common_reference_net = \"GND\"" + ] + }, + { + "cell_type": "markdown", + "id": "9847ee5f", + "metadata": {}, + "source": [ + "## Load project\n", + "\n", + "Check if the AEDT file exists and remove it to allow EDB loading. Then, load the initial EDB file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab4ee61a", + "metadata": {}, + "outputs": [], + "source": [ + "if os.path.isfile(aedt_file):\n", + " os.remove(aedt_file)\n", + "edb = Edb(edbversion=edb_version, edbpath=edb_file)" + ] + }, + { + "cell_type": "markdown", + "id": "933ee810", + "metadata": {}, + "source": [ + "## Copy project zones\n", + "\n", + "Copy project zone into the subproject." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a350af5", + "metadata": {}, + "outputs": [], + "source": [ + "edb_zones = edb.copy_zones(working_directory=work_folder)" + ] + }, + { + "cell_type": "markdown", + "id": "1411e0cb", + "metadata": {}, + "source": [ + "## Split zones\n", + "\n", + "Clip subdesigns along with corresponding zone definitions\n", + "and create a port of clipped signal traces." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ded46f4", + "metadata": {}, + "outputs": [], + "source": [ + "defined_ports, project_connexions = edb.cutout_multizone_layout(\n", + " edb_zones, common_reference_net\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8324fd77", + "metadata": {}, + "source": [ + "## Create circuit\n", + "\n", + "Create circuit design, import all subprojects as EM models, and connect\n", + "all corresponding pins in the circuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c7bd578", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = Circuit(version=edb_version, project=circuit_project_file)\n", + "circuit.connect_circuit_models_from_multi_zone_cutout(\n", + " project_connections=project_connexions,\n", + " edb_zones_dict=edb_zones,\n", + " ports=defined_ports,\n", + " model_inc=70,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "535eb2d8", + "metadata": {}, + "source": [ + "## Set up simulation\n", + "\n", + "Add Nexxim LNA simulation setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6eca12a4", + "metadata": {}, + "outputs": [], + "source": [ + "circuit_setup = circuit.create_setup(\"Pyedt_LNA\")" + ] + }, + { + "cell_type": "markdown", + "id": "74c2c254", + "metadata": {}, + "source": [ + "## Add frequency sweep\n", + "\n", + "Add a frequency sweep from 0 GHt to 20 GHz with a 10 NHz frequency step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1e7ee1c", + "metadata": {}, + "outputs": [], + "source": [ + "circuit_setup.props[\"SweepDefinition\"][\"Data\"] = \"LIN {} {} {}\".format(\n", + " \"0GHz\", \"20GHz\", \"10MHz\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f799e818", + "metadata": {}, + "source": [ + "## Start simulation\n", + "\n", + "Analyze all SIwave projects and solve the circuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23d3db88", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.analyze()" + ] + }, + { + "cell_type": "markdown", + "id": "5df1598a", + "metadata": {}, + "source": [ + "Define differential pairs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "759c54fc", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.set_differential_pair(\n", + " differential_mode=\"U0\",\n", + " assignment=\"U0.via_38.B2B_SIGP\",\n", + " reference=\"U0.via_39.B2B_SIGN\",\n", + ")\n", + "circuit.set_differential_pair(\n", + " differential_mode=\"U1\",\n", + " assignment=\"U1.via_32.B2B_SIGP\",\n", + " reference=\"U1.via_33.B2B_SIGN\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5107060c", + "metadata": {}, + "source": [ + "Plot results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51cc928f", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.post.create_report(\n", + " expressions=[\"dB(S(U0,U0))\", \"dB(S(U1,U0))\"], context=\"Differential Pairs\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d93795f1", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c224a60a", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.save_project()\n", + "circuit.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "8464a083", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2c35d11", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout.ipynb.txt new file mode 100644 index 00000000..7f0e3262 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout.ipynb.txt @@ -0,0 +1,804 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7fa2d1c8", + "metadata": {}, + "source": [ + "# Pre-layout signal integrity\n", + "This example shows how to create a parameterized layout design\n", + "and load the layout into HFSS 3D Layout for analysis and postprocessing.\n", + "\n", + "- Create EDB:\n", + "\n", + " - Add material.\n", + " - Create stackup.\n", + " - Create a parameterized via padstack definition.\n", + " - Create ground planes.\n", + " - Create a component.\n", + " - Create signal vias and traces.\n", + " - Create ground stitching vias.\n", + " - Create HFSS analysis setup and frequency sweep.\n", + "\n", + "- Import EDB into HFSS 3D Layout:\n", + "\n", + " - Place SMA connector.\n", + " - Analyze.\n", + " - Plot return loss." + ] + }, + { + "cell_type": "markdown", + "id": "c73c7db2", + "metadata": {}, + "source": [ + "Here is an image of the model that is created in this example.\n", + "\n", + "\n", + "\n", + "Keywords: **HFSS 3D Layout**, **signal integrity**." + ] + }, + { + "cell_type": "markdown", + "id": "75d93c31", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Perform required packages." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b164f282", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "from ansys.aedt.core import Hfss3dLayout\n", + "from ansys.aedt.core.downloads import download_file\n", + "from pyedb import Edb\n" + ] + }, + { + "cell_type": "markdown", + "id": "db5faab1", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e5241d3", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "086cec24", + "metadata": {}, + "source": [ + "## Create temporary directory and download example files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "349b79c5", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "sma_rf_connector = download_file(\n", + " source=\"component_3d\",\n", + " name=\"SMA_RF_SURFACE_MOUNT.a3dcomp\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0e309f66", + "metadata": {}, + "source": [ + "# Create layout design" + ] + }, + { + "cell_type": "markdown", + "id": "71636f5e", + "metadata": {}, + "source": [ + "## Import example design" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a81c6487", + "metadata": {}, + "outputs": [], + "source": [ + "aedb = os.path.join(temp_folder.name, \"new_layout.aedb\")\n", + "edbapp = Edb(edbpath=aedb, edbversion=AEDT_VERSION)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163d9bb1", + "metadata": {}, + "outputs": [], + "source": [ + "# Set antipad always on.\n", + "edbapp.design_options.antipads_always_on = True" + ] + }, + { + "cell_type": "markdown", + "id": "da7e8b5f", + "metadata": {}, + "source": [ + "## Add material definitions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7792c99", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.materials.add_conductor_material(name=\"copper\", conductivity=58000000)\n", + "edbapp.materials.add_dielectric_material(\n", + " name=\"FR4_epoxy\", permittivity=4, dielectric_loss_tangent=0.02\n", + ")\n", + "edbapp.materials.add_dielectric_material(\n", + " name=\"solder_mask\", permittivity=3.1, dielectric_loss_tangent=0.035\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1071e855", + "metadata": {}, + "source": [ + "## Create stackup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55f8a214", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.stackup.create_symmetric_stackup(\n", + " layer_count=4,\n", + " inner_layer_thickness=\"18um\",\n", + " outer_layer_thickness=\"50um\",\n", + " dielectric_thickness=\"100um\",\n", + " dielectric_material=\"FR4_epoxy\",\n", + " soldermask=True,\n", + " soldermask_thickness=\"20um\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d088f46e", + "metadata": {}, + "source": [ + "## Create parameterized padstack definition" + ] + }, + { + "cell_type": "markdown", + "id": "881f9b01", + "metadata": {}, + "source": [ + "Create signal via padstack definition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa263431", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp[\"$antipad\"] = \"0.7mm\"\n", + "edbapp.padstacks.create(\n", + " padstackname=\"svia\", holediam=\"0.3mm\", antipaddiam=\"$antipad\", paddiam=\"0.5mm\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "07714360", + "metadata": {}, + "source": [ + "Create component pin padstack definition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39107522", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.padstacks.create(\n", + " padstackname=\"comp_pin\",\n", + " paddiam=\"400um\",\n", + " antipaddiam=\"600um\",\n", + " start_layer=\"TOP\",\n", + " stop_layer=\"TOP\",\n", + " antipad_shape=\"Circle\",\n", + " has_hole=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d984839a", + "metadata": {}, + "source": [ + "## Review stackup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3854df1", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.stackup.plot(plot_definitions=\"svia\")" + ] + }, + { + "cell_type": "markdown", + "id": "9e72138b", + "metadata": {}, + "source": [ + "## Create ground planes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ff97627", + "metadata": {}, + "outputs": [], + "source": [ + "board_width = \"22mm\"\n", + "board_length = \"18mm\"\n", + "board_center_point = [0, \"5mm\"]\n", + "\n", + "gnd_l2 = edbapp.modeler.create_rectangle(\n", + " layer_name=\"L2\",\n", + " net_name=\"GND\",\n", + " center_point=board_center_point,\n", + " width=board_width,\n", + " height=board_length,\n", + " representation_type=\"CenterWidthHeight\",\n", + " corner_radius=\"0mm\",\n", + " rotation=\"0deg\",\n", + ")\n", + "\n", + "gnd_l3 = edbapp.modeler.create_rectangle(\n", + " layer_name=\"L3\",\n", + " net_name=\"GND\",\n", + " center_point=board_center_point,\n", + " width=board_width,\n", + " height=board_length,\n", + " representation_type=\"CenterWidthHeight\",\n", + " corner_radius=\"0mm\",\n", + " rotation=\"0deg\",\n", + ")\n", + "\n", + "gnd_bottom = edbapp.modeler.create_rectangle(\n", + " layer_name=\"BOT\",\n", + " net_name=\"GND\",\n", + " center_point=board_center_point,\n", + " width=board_width,\n", + " height=board_length,\n", + " representation_type=\"CenterWidthHeight\",\n", + " corner_radius=\"0mm\",\n", + " rotation=\"0deg\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1c564887", + "metadata": {}, + "source": [ + "## Create a component" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e638617", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.padstacks.place(\n", + " position=[0, 0],\n", + " definition_name=\"comp_pin\",\n", + " net_name=\"SIG\",\n", + " is_pin=True,\n", + " via_name=\"1\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02423799", + "metadata": {}, + "outputs": [], + "source": [ + "comp_pins = [\n", + " edbapp.padstacks.place(\n", + " position=[\"-6mm\", 0],\n", + " definition_name=\"comp_pin\",\n", + " net_name=\"GND\",\n", + " is_pin=True,\n", + " via_name=\"2\",\n", + " ),\n", + " edbapp.padstacks.place(\n", + " position=[\"6mm\", 0],\n", + " definition_name=\"comp_pin\",\n", + " net_name=\"GND\",\n", + " is_pin=True,\n", + " via_name=\"3\",\n", + " ),\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36791c0c", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "comp_u1 = edbapp.components.create(\n", + " pins=comp_pins,\n", + " component_name=\"U1\",\n", + " component_part_name=\"BGA\",\n", + " placement_layer=\"TOP\",\n", + ")\n", + "comp_u1.create_clearance_on_component(extra_soldermask_clearance=3.5e-3)" + ] + }, + { + "cell_type": "markdown", + "id": "44307e56", + "metadata": {}, + "source": [ + "## Place vias" + ] + }, + { + "cell_type": "markdown", + "id": "f51803f8", + "metadata": {}, + "source": [ + "Place a signal via." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6760d279", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.padstacks.place(\n", + " position=[0, 0], definition_name=\"svia\", net_name=\"SIG\", is_pin=False\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "260f0d99", + "metadata": {}, + "source": [ + "Place ground stitching vias." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38966ad9", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.padstacks.place(\n", + " position=[\"-1mm\", 0], definition_name=\"svia\", net_name=\"GND\", is_pin=False\n", + ")\n", + "edbapp.padstacks.place(\n", + " position=[\"1mm\", 0], definition_name=\"svia\", net_name=\"GND\", is_pin=False\n", + ")\n", + "edbapp.padstacks.place(\n", + " position=[0, \"-1mm\"], definition_name=\"svia\", net_name=\"GND\", is_pin=False\n", + ")\n", + "edbapp.padstacks.place(\n", + " position=[0, \"1mm\"], definition_name=\"svia\", net_name=\"GND\", is_pin=False\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b9d03460", + "metadata": {}, + "source": [ + "## Create signal traces" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "653af08f", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp[\"width\"] = \"0.15mm\"\n", + "edbapp[\"gap\"] = \"0.1mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "99f15e6d", + "metadata": {}, + "source": [ + "Create signal fanout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29fc93e2", + "metadata": {}, + "outputs": [], + "source": [ + "sig_trace = edbapp.modeler.create_trace(\n", + " path_list=[[0, 0]],\n", + " layer_name=\"BOT\",\n", + " width=\"width\",\n", + " net_name=\"SIG\",\n", + " start_cap_style=\"Round\",\n", + " end_cap_style=\"Round\",\n", + " corner_style=\"Round\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e42b3ed2", + "metadata": {}, + "outputs": [], + "source": [ + "sig_trace.add_point(x=\"0.5mm\", y=\"0.5mm\", incremental=True)\n", + "sig_trace.add_point(x=0, y=\"1mm\", incremental=True)\n", + "sig_trace.add_point(x=\"-0.5mm\", y=\"0.5mm\", incremental=True)\n", + "sig_trace.add_point(x=0, y=\"1mm\", incremental=True)\n", + "sig_path = sig_trace.get_center_line()" + ] + }, + { + "cell_type": "markdown", + "id": "03854bea", + "metadata": {}, + "source": [ + "Create coplanar waveguide with ground with ground stitching vias." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5868ee5", + "metadata": {}, + "outputs": [], + "source": [ + "sig2_trace = edbapp.modeler.create_trace(\n", + " path_list=[sig_path[-1]],\n", + " layer_name=\"BOT\",\n", + " width=\"width\",\n", + " net_name=\"SIG\",\n", + " start_cap_style=\"Round\",\n", + " end_cap_style=\"Flat\",\n", + " corner_style=\"Round\",\n", + ")\n", + "sig2_trace.add_point(x=0, y=\"6mm\", incremental=True)\n", + "sig2_trace.create_via_fence(distance=\"0.5mm\", gap=\"1mm\", padstack_name=\"svia\")\n", + "sig2_trace.add_point(x=0, y=\"1mm\", incremental=True)" + ] + }, + { + "cell_type": "markdown", + "id": "0765f884", + "metadata": {}, + "source": [ + "Create trace-to-ground clearance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4514daf4", + "metadata": {}, + "outputs": [], + "source": [ + "sig2_path = sig2_trace.get_center_line()\n", + "path_list = [sig_path, sig2_path]\n", + "for i in path_list:\n", + " void = edbapp.modeler.create_trace(\n", + " path_list=i,\n", + " layer_name=\"BOT\",\n", + " width=\"width+gap*2\",\n", + " start_cap_style=\"Round\",\n", + " end_cap_style=\"Round\",\n", + " corner_style=\"Round\",\n", + " )\n", + " edbapp.modeler.add_void(shape=gnd_bottom, void_shape=void)" + ] + }, + { + "cell_type": "markdown", + "id": "876f500e", + "metadata": {}, + "source": [ + "Generate plot to review." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d1f9519", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.nets.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "2c1deaa6", + "metadata": {}, + "source": [ + "## Create ports" + ] + }, + { + "cell_type": "markdown", + "id": "9c86fbc1", + "metadata": {}, + "source": [ + "Create a wave port." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5ea1aa3", + "metadata": {}, + "outputs": [], + "source": [ + "sig2_trace.create_edge_port(\n", + " name=\"p1_wave_port\",\n", + " position=\"End\",\n", + " port_type=\"Wave\",\n", + " reference_layer=None,\n", + " horizontal_extent_factor=10,\n", + " vertical_extent_factor=10,\n", + " pec_launch_width=\"0.01mm\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c33ffd86", + "metadata": {}, + "source": [ + "## Create HFSS analysis setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65836590", + "metadata": {}, + "outputs": [], + "source": [ + "setup = edbapp.create_hfss_setup(\"Setup1\")\n", + "setup.set_solution_single_frequency(\"5GHz\", max_num_passes=1, max_delta_s=\"0.02\")\n", + "setup.hfss_solver_settings.order_basis = \"first\"" + ] + }, + { + "cell_type": "markdown", + "id": "46f737c8", + "metadata": {}, + "source": [ + "Add a frequency sweep to the setup.\n", + "\n", + "When the simulation results are to\n", + "be used for transient SPICE analysis, you should\n", + "use the following strategy:\n", + "\n", + "- DC point\n", + "- Logarithmic sweep from 1 kHz to 100 MHz\n", + "- Linear scale for higher frequencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05669094", + "metadata": {}, + "outputs": [], + "source": [ + "setup.add_frequency_sweep(\n", + " \"Sweep1\",\n", + " frequency_sweep=[\n", + " [\"log scale\", \"10MHz\", \"100MHz\", 3],\n", + " [\"linear scale\", \"0.1GHz\", \"5GHz\", \"0.2GHz\"],\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1f026967", + "metadata": {}, + "source": [ + "## Save and close EDB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "938a82b1", + "metadata": {}, + "outputs": [], + "source": [ + "edbapp.save()\n", + "edbapp.close()" + ] + }, + { + "cell_type": "markdown", + "id": "b00d6066", + "metadata": {}, + "source": [ + "# Analyze in HFSS 3D Layout" + ] + }, + { + "cell_type": "markdown", + "id": "857db99d", + "metadata": {}, + "source": [ + "## Load EDB into HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad3eb878", + "metadata": {}, + "outputs": [], + "source": [ + "h3d = Hfss3dLayout(aedb, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True)" + ] + }, + { + "cell_type": "markdown", + "id": "70ab1587", + "metadata": {}, + "source": [ + "## Place SMA RF connector" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa264ca1", + "metadata": {}, + "outputs": [], + "source": [ + "comp = h3d.modeler.place_3d_component(\n", + " component_path=sma_rf_connector,\n", + " number_of_terminals=1,\n", + " placement_layer=\"TOP\",\n", + " component_name=\"sma_rf\",\n", + " pos_x=0,\n", + " pos_y=0,\n", + " create_ports=True,\n", + ")\n", + "comp.angle = \"90deg\"" + ] + }, + { + "cell_type": "markdown", + "id": "730a11d9", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f94744e", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.save_project()\n", + "h3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "50534c2b", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_dir.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "242b10dc", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout_parametrized.ipynb.txt b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout_parametrized.ipynb.txt new file mode 100644 index 00000000..0ef379a7 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/layout/signal_integrity/pre_layout_parametrized.ipynb.txt @@ -0,0 +1,822 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f2c84098", + "metadata": {}, + "source": [ + "# Pre-layout Parameterized PCB\n", + "\n", + "This example shows how to use the EDB interface along with HFSS 3D Layout to create and solve a\n", + "parameterized layout. The layout shows a differential via transition on a printed circuit board\n", + "with back-to-back microstrip to stripline transitions.\n", + "The model is fully parameterized to enable investigation of the transition performance on the\n", + "many degrees of freedom.\n", + "\n", + "The resulting model is shown below\n", + "\n", + "" + ] + }, + { + "cell_type": "markdown", + "id": "e52726df", + "metadata": {}, + "source": [ + "## Preparation\n", + "Import the required packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b29e6b02", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "from ansys.aedt.core import Hfss3dLayout\n", + "from pyedb import Edb\n" + ] + }, + { + "cell_type": "markdown", + "id": "f5b909dd", + "metadata": {}, + "source": [ + "## Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53473a80", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "5671d2cc", + "metadata": {}, + "source": [ + "## Launch EDB" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b557dc7f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "aedb_path = os.path.join(temp_folder.name, \"pcb.aedb\")\n", + "edb = Edb(edbpath=aedb_path, edbversion=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "a8c2a31f", + "metadata": {}, + "source": [ + "## Create layout\n", + "### Define the parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75c02ae7", + "metadata": {}, + "outputs": [], + "source": [ + "params = {\n", + " \"$ms_width\": \"0.4mm\",\n", + " \"$sl_width\": \"0.2mm\",\n", + " \"$ms_spacing\": \"0.2mm\",\n", + " \"$sl_spacing\": \"0.1mm\",\n", + " \"$via_spacing\": \"0.5mm\",\n", + " \"$via_diam\": \"0.3mm\",\n", + " \"$pad_diam\": \"0.6mm\",\n", + " \"$anti_pad_diam\": \"0.7mm\",\n", + " \"$pcb_len\": \"15mm\",\n", + " \"$pcb_w\": \"5mm\",\n", + " \"$x_size\": \"1.2mm\",\n", + " \"$y_size\": \"1mm\",\n", + " \"$corner_rad\": \"0.5mm\",\n", + "}\n", + "\n", + "for par_name in params:\n", + " edb.add_project_variable(par_name, params[par_name])" + ] + }, + { + "cell_type": "markdown", + "id": "d3a43893", + "metadata": {}, + "source": [ + "### Create stackup\n", + "Define the stackup layers from bottom to top." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad490282", + "metadata": {}, + "outputs": [], + "source": [ + "layers = [\n", + " {\n", + " \"name\": \"bottom\",\n", + " \"layer_type\": \"signal\",\n", + " \"thickness\": \"35um\",\n", + " \"material\": \"copper\",\n", + " },\n", + " {\n", + " \"name\": \"diel_3\",\n", + " \"layer_type\": \"dielectric\",\n", + " \"thickness\": \"275um\",\n", + " \"material\": \"FR4_epoxy\",\n", + " },\n", + " {\n", + " \"name\": \"sig_2\",\n", + " \"layer_type\": \"signal\",\n", + " \"thickness\": \"35um\",\n", + " \"material\": \"copper\",\n", + " },\n", + " {\n", + " \"name\": \"diel_2\",\n", + " \"layer_type\": \"dielectric\",\n", + " \"thickness\": \"275um\",\n", + " \"material\": \"FR4_epoxy\",\n", + " },\n", + " {\n", + " \"name\": \"sig_1\",\n", + " \"layer_type\": \"signal\",\n", + " \"thickness\": \"35um\",\n", + " \"material\": \"copper\",\n", + " },\n", + " {\n", + " \"name\": \"diel_1\",\n", + " \"layer_type\": \"dielectric\",\n", + " \"thickness\": \"275um\",\n", + " \"material\": \"FR4_epoxy\",\n", + " },\n", + " {\"name\": \"top\", \"layer_type\": \"signal\", \"thickness\": \"35um\", \"material\": \"copper\"},\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "24693665", + "metadata": {}, + "source": [ + "Define the bottom layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb4c6078", + "metadata": {}, + "outputs": [], + "source": [ + "prev = None\n", + "for layer in layers:\n", + " edb.stackup.add_layer(\n", + " layer[\"name\"],\n", + " base_layer=prev,\n", + " layer_type=layer[\"layer_type\"],\n", + " thickness=layer[\"thickness\"],\n", + " material=layer[\"material\"],\n", + " )\n", + " prev = layer[\"name\"]" + ] + }, + { + "cell_type": "markdown", + "id": "8819e7e7", + "metadata": {}, + "source": [ + "### Create a parametrized padstack for the signal via.\n", + "Create a padstack definition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dccbe2f9", + "metadata": {}, + "outputs": [], + "source": [ + "signal_via_padstack = \"automated_via\"\n", + "edb.padstacks.create(\n", + " padstackname=signal_via_padstack,\n", + " holediam=\"$via_diam\",\n", + " paddiam=\"$pad_diam\",\n", + " antipaddiam=\"\",\n", + " antipad_shape=\"Bullet\",\n", + " x_size=\"$x_size\",\n", + " y_size=\"$y_size\",\n", + " corner_radius=\"$corner_rad\",\n", + " start_layer=layers[-1][\"name\"],\n", + " stop_layer=layers[-3][\"name\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cb8f3d03", + "metadata": {}, + "source": [ + "Assign net names. There are only two signal nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b849638", + "metadata": {}, + "outputs": [], + "source": [ + "net_p = \"p\"\n", + "net_n = \"n\"" + ] + }, + { + "cell_type": "markdown", + "id": "a6bf0c61", + "metadata": {}, + "source": [ + "Place the signal vias." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5169015e", + "metadata": {}, + "outputs": [], + "source": [ + "edb.padstacks.place(\n", + " position=[\"$pcb_len/3\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " definition_name=signal_via_padstack,\n", + " net_name=net_p,\n", + " via_name=\"\",\n", + " rotation=90.0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e640b20", + "metadata": {}, + "outputs": [], + "source": [ + "edb.padstacks.place(\n", + " position=[\"2*$pcb_len/3\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " definition_name=signal_via_padstack,\n", + " net_name=net_p,\n", + " via_name=\"\",\n", + " rotation=90.0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d62c929", + "metadata": {}, + "outputs": [], + "source": [ + "edb.padstacks.place(\n", + " position=[\"$pcb_len/3\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " definition_name=signal_via_padstack,\n", + " net_name=net_n,\n", + " via_name=\"\",\n", + " rotation=-90.0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92df7f12", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "edb.padstacks.place(\n", + " position=[\"2*$pcb_len/3\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " definition_name=signal_via_padstack,\n", + " net_name=net_n,\n", + " via_name=\"\",\n", + " rotation=-90.0,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7437c440", + "metadata": {}, + "source": [ + "### Draw parametrized traces\n", + "\n", + "Trace width and the routing (Microstrip-Stripline-Microstrip).\n", + "Applies to both p and n nets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "529816e9", + "metadata": {}, + "outputs": [], + "source": [ + "# Trace width, n and p\n", + "width = [\"$ms_width\", \"$sl_width\", \"$ms_width\"]\n", + "# Routing layer, n and p\n", + "route_layer = [layers[-1][\"name\"], layers[4][\"name\"], layers[-1][\"name\"]]" + ] + }, + { + "cell_type": "markdown", + "id": "eb184ee3", + "metadata": {}, + "source": [ + "Define points for three traces in the \"p\" net" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "339d8651", + "metadata": {}, + "outputs": [], + "source": [ + "points_p = [\n", + " [\n", + " [\"0.0\", \"($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len/3-2*$via_spacing\", \"($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len/3-$via_spacing\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " ],\n", + " [\n", + " [\"$pcb_len/3\", \"($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3+$via_spacing\", \"($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3+2*$via_spacing\", \"($sl_width+$sl_spacing)/2\"],\n", + " [\"2*$pcb_len/3-2*$via_spacing\", \"($sl_width+$sl_spacing)/2\"],\n", + " [\"2*$pcb_len/3-$via_spacing\", \"($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3\", \"($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " ],\n", + " [\n", + " [\"2*$pcb_len/3\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3+$via_spacing\", \"($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3+2*$via_spacing\", \"($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len\", \"($ms_width+$ms_spacing)/2\"],\n", + " ],\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "6b5eba2d", + "metadata": {}, + "source": [ + "Define points for three traces in the \"n\" net" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cc0c68b", + "metadata": {}, + "outputs": [], + "source": [ + "points_n = [\n", + " [\n", + " [\"0.0\", \"-($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len/3-2*$via_spacing\", \"-($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len/3-$via_spacing\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " ],\n", + " [\n", + " [\"$pcb_len/3\", \"-($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3+$via_spacing\", \"-($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"$pcb_len/3+2*$via_spacing\", \"-($ms_width+$sl_spacing)/2\"],\n", + " [\"2*$pcb_len/3-2*$via_spacing\", \"-($ms_width+$sl_spacing)/2\"],\n", + " [\"2*$pcb_len/3-$via_spacing\", \"-($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3\", \"-($ms_width+$sl_spacing+$via_spacing)/2\"],\n", + " ],\n", + " [\n", + " [\"2*$pcb_len/3\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3 + $via_spacing\", \"-($ms_width+$ms_spacing+$via_spacing)/2\"],\n", + " [\"2*$pcb_len/3 + 2*$via_spacing\", \"-($ms_width+$ms_spacing)/2\"],\n", + " [\"$pcb_len\", \"-($ms_width + $ms_spacing)/2\"],\n", + " ],\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "3ad8361b", + "metadata": {}, + "source": [ + "Add traces to the EDB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b19afb9", + "metadata": {}, + "outputs": [], + "source": [ + "trace_p = []\n", + "trace_n = []\n", + "for n in range(len(points_p)):\n", + " trace_p.append(\n", + " edb.modeler.create_trace(\n", + " points_p[n], route_layer[n], width[n], net_p, \"Flat\", \"Flat\"\n", + " )\n", + " )\n", + " trace_n.append(\n", + " edb.modeler.create_trace(\n", + " points_n[n], route_layer[n], width[n], net_n, \"Flat\", \"Flat\"\n", + " )\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "43704113", + "metadata": {}, + "source": [ + "Create the wave ports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b70a0d88", + "metadata": {}, + "outputs": [], + "source": [ + "edb.hfss.create_differential_wave_port(\n", + " trace_p[0].id,\n", + " [\"0.0\", \"($ms_width+$ms_spacing)/2\"],\n", + " trace_n[0].id,\n", + " [\"0.0\", \"-($ms_width+$ms_spacing)/2\"],\n", + " \"wave_port_1\",\n", + ")\n", + "edb.hfss.create_differential_wave_port(\n", + " trace_p[2].id,\n", + " [\"$pcb_len\", \"($ms_width+$ms_spacing)/2\"],\n", + " trace_n[2].id,\n", + " [\"$pcb_len\", \"-($ms_width + $ms_spacing)/2\"],\n", + " \"wave_port_2\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2e0be10b", + "metadata": {}, + "source": [ + "Draw a conducting rectangle on the the ground layers." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc396461", + "metadata": {}, + "outputs": [], + "source": [ + "gnd_poly = [\n", + " [0.0, \"-$pcb_w/2\"],\n", + " [\"$pcb_len\", \"-$pcb_w/2\"],\n", + " [\"$pcb_len\", \"$pcb_w/2\"],\n", + " [0.0, \"$pcb_w/2\"],\n", + "]\n", + "gnd_shape = edb.modeler.Shape(\"polygon\", points=gnd_poly)" + ] + }, + { + "cell_type": "markdown", + "id": "ccb81017", + "metadata": {}, + "source": [ + "Void in ground for traces on the signal routing layer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ee918eb", + "metadata": {}, + "outputs": [], + "source": [ + "void_poly = [\n", + " [\n", + " \"$pcb_len/3\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"$pcb_len/3 + $via_spacing\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"$pcb_len/3 + 2*$via_spacing\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3 - 2*$via_spacing\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3 - $via_spacing\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3\",\n", + " \"-($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2-$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3 - $via_spacing\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"2*$pcb_len/3 - 2*$via_spacing\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2\",\n", + " ],\n", + " [\n", + " \"$pcb_len/3 + 2*$via_spacing\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2\",\n", + " ],\n", + " [\n", + " \"$pcb_len/3 + $via_spacing\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2\",\n", + " ],\n", + " [\n", + " \"$pcb_len/3\",\n", + " \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2+$via_spacing/2\",\n", + " ],\n", + " [\"$pcb_len/3\", \"($ms_width+$ms_spacing+$via_spacing+$anti_pad_diam)/2\"],\n", + "]\n", + "\n", + "void_shape = edb.modeler.Shape(\"polygon\", points=void_poly)" + ] + }, + { + "cell_type": "markdown", + "id": "79703ac4", + "metadata": {}, + "source": [ + "Add ground conductors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c30b1f09", + "metadata": {}, + "outputs": [], + "source": [ + "for layer in layers[:-1:2]:\n", + "\n", + " # add void if the layer is the signal routing layer.\n", + " void = [void_shape] if layer[\"name\"] == route_layer[1] else []\n", + "\n", + " edb.modeler.create_polygon(\n", + " main_shape=gnd_shape, layer_name=layer[\"name\"], voids=void, net_name=\"gnd\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "80c4881a", + "metadata": {}, + "source": [ + "Plot the layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aea7a454", + "metadata": {}, + "outputs": [], + "source": [ + "edb.nets.plot(None)" + ] + }, + { + "cell_type": "markdown", + "id": "e6fcab61", + "metadata": {}, + "source": [ + "Save the EDB." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b6b27cd", + "metadata": {}, + "outputs": [], + "source": [ + "edb.save_edb()\n", + "edb.close_edb()" + ] + }, + { + "cell_type": "markdown", + "id": "9ff5426f", + "metadata": {}, + "source": [ + "## Open the project in HFSS 3D Layout." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c83bff0", + "metadata": {}, + "outputs": [], + "source": [ + "h3d = Hfss3dLayout(\n", + " project=aedb_path,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "289a78ec", + "metadata": {}, + "source": [ + "### Add a HFSS simulation setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6aa08ea", + "metadata": {}, + "outputs": [], + "source": [ + "setup = h3d.create_setup()\n", + "setup.props[\"AdaptiveSettings\"][\"SingleFrequencyDataList\"][\"AdaptiveFrequencyData\"][\n", + " \"MaxPasses\"\n", + "] = 3\n", + "\n", + "h3d.create_linear_count_sweep(\n", + " setup=setup.name,\n", + " unit=\"GHz\",\n", + " start_frequency=0,\n", + " stop_frequency=10,\n", + " num_of_freq_points=1001,\n", + " name=\"sweep1\",\n", + " sweep_type=\"Interpolating\",\n", + " interpolation_tol_percent=1,\n", + " interpolation_max_solutions=255,\n", + " save_fields=False,\n", + " use_q3d_for_dc=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7d6855eb", + "metadata": {}, + "source": [ + "### Define the differential pairs to used to calculate differential and common mode s-parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07f01159", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.set_differential_pair(\n", + " differential_mode=\"In\", assignment=\"wave_port_1:T1\", reference=\"wave_port_1:T2\"\n", + ")\n", + "h3d.set_differential_pair(\n", + " differential_mode=\"Out\", assignment=\"wave_port_2:T1\", reference=\"wave_port_2:T2\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7275d4aa", + "metadata": {}, + "source": [ + "Solve the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a904a18", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "8c00d260", + "metadata": {}, + "source": [ + "Plot the results and shut down AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4e68950", + "metadata": {}, + "outputs": [], + "source": [ + "solutions = h3d.post.get_solution_data(\n", + " expressions=[\"dB(S(In,In))\", \"dB(S(In,Out))\"], context=\"Differential Pairs\"\n", + ")\n", + "solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "84e9aee8", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bf18a39", + "metadata": {}, + "outputs": [], + "source": [ + "h3d.save_project()\n", + "h3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "371b82e5", + "metadata": {}, + "source": [ + "Note that the ground nets are only connected to each other due\n", + "to the wave ports. The problem with poor grounding can be seen in the\n", + "S-parameters. This example can be downloaded as a Jupyter Notebook, so\n", + "you can modify it. Try changing parameters or adding ground vias to improve performance.\n", + "\n", + "The final cell cleans up the temporary directory, removing all files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23bc2aa4", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/multiphysics/hfss_mechanical.ipynb.txt b/version/dev/_sources/examples/high_frequency/multiphysics/hfss_mechanical.ipynb.txt new file mode 100644 index 00000000..c01c7eb2 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/multiphysics/hfss_mechanical.ipynb.txt @@ -0,0 +1,391 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9bc60f8c", + "metadata": {}, + "source": [ + "# HFSS-Mechanical multiphysics analysis\n", + "\n", + "This example shows how to use PyAEDT to create a multiphysics workflow that\n", + "includes Circuit, HFSS, and Mechanical.\n", + "\n", + "Keywords: **Multiphysics**, **HFSS**, **Mechanical AEDT**, **Circuit**." + ] + }, + { + "cell_type": "markdown", + "id": "69c363bd", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ed4703f", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "eafe5553", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e892db2d", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "fdaca12f", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92e2d8f5", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "17d41cfd", + "metadata": {}, + "source": [ + "## Download and open project\n", + "\n", + "Download and open the project. Save it to the temporary folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efc86848", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = ansys.aedt.core.downloads.download_via_wizard(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "433275e4", + "metadata": {}, + "source": [ + "## Start HFSS\n", + "\n", + "Initialize HFSS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d0b2bfc", + "metadata": {}, + "outputs": [], + "source": [ + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "hfss.change_material_override(True)" + ] + }, + { + "cell_type": "markdown", + "id": "48db10b0", + "metadata": {}, + "source": [ + "## Initialize Circuit\n", + "\n", + "Initialize Circuit and add the HFSS dynamic link component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9f795be", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = ansys.aedt.core.Circuit(version=AEDT_VERSION)\n", + "hfss_comp = circuit.modeler.schematic.add_subcircuit_dynamic_link(pyaedt_app=hfss)" + ] + }, + { + "cell_type": "markdown", + "id": "5cc21db9", + "metadata": {}, + "source": [ + "## Set up dynamic link options\n", + "\n", + "Set up dynamic link options. The argument for the ``set_sim_option_on_hfss_subcircuit()``\n", + "method can be the component name, component ID, or component object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "727de079", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.modeler.schematic.refresh_dynamic_link(name=hfss_comp.composed_name)\n", + "circuit.modeler.schematic.set_sim_option_on_hfss_subcircuit(component=hfss_comp)\n", + "hfss_setup_name = hfss.setups[0].name + \" : \" + hfss.setups[0].sweeps[0].name\n", + "circuit.modeler.schematic.set_sim_solution_on_hfss_subcircuit(\n", + " component=hfss_comp.composed_name, solution_name=hfss_setup_name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9eeb7b6a", + "metadata": {}, + "source": [ + "## Create ports and excitations\n", + "\n", + "Create ports and excitations. Find component pin locations and create interface\n", + "ports on them. Define the voltage source on the input port." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ff78ffc", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.modeler.schematic.create_interface_port(\n", + " name=\"Excitation_1\",\n", + " location=[hfss_comp.pins[0].location[0], hfss_comp.pins[0].location[1]],\n", + ")\n", + "circuit.modeler.schematic.create_interface_port(\n", + " name=\"Excitation_2\",\n", + " location=[hfss_comp.pins[1].location[0], hfss_comp.pins[1].location[1]],\n", + ")\n", + "circuit.modeler.schematic.create_interface_port(\n", + " name=\"Port_1\",\n", + " location=[hfss_comp.pins[2].location[0], hfss_comp.pins[2].location[1]],\n", + ")\n", + "circuit.modeler.schematic.create_interface_port(\n", + " name=\"Port_2\",\n", + " location=[hfss_comp.pins[3].location[0], hfss_comp.pins[3].location[1]],\n", + ")\n", + "\n", + "ports_list = [\"Excitation_1\", \"Excitation_2\"]\n", + "source = circuit.assign_voltage_sinusoidal_excitation_to_ports(ports_list)\n", + "source.ac_magnitude = 1\n", + "source.phase = 0" + ] + }, + { + "cell_type": "markdown", + "id": "7fe4b922", + "metadata": {}, + "source": [ + "## Create setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c630114", + "metadata": {}, + "outputs": [], + "source": [ + "setup_name = \"MySetup\"\n", + "LNA_setup = circuit.create_setup(name=setup_name)\n", + "sweep_list = [\"LINC\", str(4.3) + \"GHz\", str(4.4) + \"GHz\", str(1001)]\n", + "LNA_setup.props[\"SweepDefinition\"][\"Data\"] = \" \".join(sweep_list)" + ] + }, + { + "cell_type": "markdown", + "id": "0b197fae", + "metadata": {}, + "source": [ + "## Solve and push excitations\n", + "\n", + "Solve the circuit and push excitations to the HFSS model to calculate the\n", + "correct value of losses." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "47f92d7f", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.analyze(cores=NUM_CORES)\n", + "circuit.push_excitations(instance=\"S1\", setup=setup_name)" + ] + }, + { + "cell_type": "markdown", + "id": "f4124686", + "metadata": {}, + "source": [ + "## Start Mechanical\n", + "\n", + "Start Mechanical and copy bodies from the HFSS project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ad0d045", + "metadata": {}, + "outputs": [], + "source": [ + "mech = ansys.aedt.core.Mechanical(version=AEDT_VERSION)\n", + "mech.copy_solid_bodies_from(design=hfss)\n", + "mech.change_material_override(True)" + ] + }, + { + "cell_type": "markdown", + "id": "9c5284b1", + "metadata": {}, + "source": [ + "## Get losses from HFSS and assign convection to Mechanical" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9a473ff", + "metadata": {}, + "outputs": [], + "source": [ + "mech.assign_em_losses(\n", + " design=hfss.design_name,\n", + " setup=hfss.setups[0].name,\n", + " sweep=\"LastAdaptive\",\n", + " map_frequency=hfss.setups[0].props[\"Frequency\"],\n", + " surface_objects=hfss.get_all_conductors_names(),\n", + ")\n", + "diels = [\"1_pd\", \"2_pd\", \"3_pd\", \"4_pd\", \"5_pd\"]\n", + "for el in diels:\n", + " mech.assign_uniform_convection(\n", + " assignment=[mech.modeler[el].top_face_y, mech.modeler[el].bottom_face_y],\n", + " convection_value=3,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "88434ee8", + "metadata": {}, + "source": [ + "## Solve and plot thermal results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f4413ab", + "metadata": {}, + "outputs": [], + "source": [ + "mech.create_setup()\n", + "mech.save_project()\n", + "mech.analyze(cores=NUM_CORES)\n", + "surfaces = []\n", + "for name in mech.get_all_conductors_names():\n", + " surfaces.extend(mech.modeler.get_object_faces(name))\n", + "mech.post.create_fieldplot_surface(assignment=surfaces, quantity=\"Temperature\")" + ] + }, + { + "cell_type": "markdown", + "id": "eb328928", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36d1623f", + "metadata": {}, + "outputs": [], + "source": [ + "mech.save_project()\n", + "mech.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "362ccecb", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ec49339", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/multiphysics/index.rst.txt b/version/dev/_sources/examples/high_frequency/multiphysics/index.rst.txt new file mode 100644 index 00000000..9b6d012f --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/multiphysics/index.rst.txt @@ -0,0 +1,102 @@ +Multiphysics +~~~~~~~~~~~~ + +These examples use PyAEDT to show some multiphysics applications. + + +.. grid:: 2 + + .. grid-item-card:: HFSS-Mechanical MRI analysis + :padding: 2 2 2 2 + :link: mri + :link-type: doc + + .. image:: _static/mri.png + :alt: MRI + :width: 250px + :height: 200px + :align: center + + This example uses a coil tuned to 63.8 MHz to determine the temperature rise in a gel phantom near + an implant given a background SAR of 1 W/kg. + + .. grid-item-card:: HFSS-Mechanical multiphysics analysis + :padding: 2 2 2 2 + :link: hfss_mechanical + :link-type: doc + + .. image:: _static/hfss_mechanical.png + :alt: HFSS Mechanical + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a multiphysics workflow that includes Circuit, HFSS, and Mechanical. + + + .. grid-item-card:: Import of a PCB and its components via IDF and EDB + :padding: 2 2 2 2 + :link: ../../electrothermal/ecad_import + :link-type: doc + + .. image:: ../../electrothermal/_static/ecad.png + :alt: Icepak ECAD + :width: 250px + :height: 200px + :align: center + + This example shows how to import a PCB and its components using IDF files (LDB and BDF). + You can also use a combination of EMN and EMP files in a similar way. + + .. grid-item-card:: Coaxial + :padding: 2 2 2 2 + :link: ../../electrothermal/coaxial_hfss_icepak + :link-type: doc + + .. image:: ../../electrothermal/_static/coaxial.png + :alt: Coaxial + :width: 250px + :height: 200px + :align: center + + This example shows how to create a project from scratch in HFSS and Icepak. + + .. grid-item-card:: Electrothermal analysis + :padding: 2 2 2 2 + :link: ../../electrothermal/electrothermal + :link-type: doc + + .. image:: ../../electrothermal/_static/electrothermal.png + :alt: Electrothermal + :width: 250px + :height: 200px + :align: center + + This example shows how to use the EDB for DC IR analysis and electrothermal analysis. + The EDB is loaded into SIwave for analysis and postprocessing. + In the end, an Icepak project is exported from SIwave. + + .. grid-item-card:: Circuit-HFSS-Icepak coupling workflow + :padding: 2 2 2 2 + :link: ../../electrothermal/icepak_circuit_hfss_coupling + :link-type: doc + + .. image:: ../../electrothermal/_static/ring.png + :alt: Ring + :width: 250px + :height: 200px + :align: center + + This example shows how to create a two-way coupling between HFSS and Icepak. + + + .. toctree:: + :hidden: + + mri + hfss_mechanical + ../../electrothermal/ecad_import + ../../electrothermal/coaxial_hfss_icepak + ../../electrothermal/electrothermal + ../../electrothermal/icepak_circuit_hfss_coupling + diff --git a/version/dev/_sources/examples/high_frequency/multiphysics/mri.ipynb.txt b/version/dev/_sources/examples/high_frequency/multiphysics/mri.ipynb.txt new file mode 100644 index 00000000..8245707e --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/multiphysics/mri.ipynb.txt @@ -0,0 +1,738 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "12762e23", + "metadata": {}, + "source": [ + "# HFSS-Mechanical MRI analysis\n", + "\n", + "This example uses a coil tuned to 63.8 MHz to determine the temperature\n", + "rise in a gel phantom near an implant given a background SAR of 1 W/kg.\n", + "\n", + "Here is the workflow:" + ] + }, + { + "cell_type": "markdown", + "id": "7d5cff63", + "metadata": {}, + "source": [ + "Step 1: Simulate the coil loaded by the empty phantom:\n", + "Scale input to coil ports to produce desired background SAR of 1 W/kg at the location\n", + "that is to contain the implant." + ] + }, + { + "cell_type": "markdown", + "id": "76129437", + "metadata": {}, + "source": [ + "Step 2: Simulate the coil loaded by the phantom containing the implant in the proper location:\n", + "View SAR in the tissue surrounding implant." + ] + }, + { + "cell_type": "markdown", + "id": "3aca3a5d", + "metadata": {}, + "source": [ + "Step 3: Thermal simulation:\n", + "Link HFSS to the transient thermal solver to find the temperature rise in the tissue near the implant\n", + "versus the time.\n", + "\n", + "Keywords: **multiphysics**, **HFSS**, **Mechanical AEDT**, **Circuit**." + ] + }, + { + "cell_type": "markdown", + "id": "086e8945", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c086812", + "metadata": {}, + "outputs": [], + "source": [ + "import os.path\n", + "import tempfile\n", + "import time\n", + "\n", + "from ansys.aedt.core import Hfss, Icepak, Mechanical, downloads\n" + ] + }, + { + "cell_type": "markdown", + "id": "d5de1e81", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09430d3b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "39cfb160", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54f8d03a", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "fbf058ab", + "metadata": {}, + "source": [ + "## Load project\n", + "\n", + "Open AEDT and the ``background_SAR.aedt`` project. This project\n", + "contains the phantom and airbox. The phantom consists of two objects: ``phantom`` and ``implant_box``.\n", + "\n", + "Separate objects are used to selectively assign mesh operations.\n", + "Material properties defined in this project already contain electrical and thermal properties." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53aeeee0", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = downloads.download_file(source=\"mri\", destination=temp_folder.name)\n", + "project_name = os.path.join(project_path, \"background_SAR.aedt\")\n", + "hfss = Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "beb61371", + "metadata": {}, + "source": [ + "## Insert 3D component\n", + "\n", + "The MRI coil is saved as a separate 3D component." + ] + }, + { + "cell_type": "markdown", + "id": "e9473ef3", + "metadata": {}, + "source": [ + "‒ 3D components store geometry (including parameters),\n", + "material properties, boundary conditions, mesh assignments,\n", + "and excitations.\n", + "‒ 3D components make it easy to reuse and share parts of a simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f9ba9e7", + "metadata": {}, + "outputs": [], + "source": [ + "component_file = os.path.join(project_path, \"coil.a3dcomp\")\n", + "hfss.modeler.insert_3d_component(input_file=component_file)" + ] + }, + { + "cell_type": "markdown", + "id": "3ede18e9", + "metadata": {}, + "source": [ + "## Define convergence criteria\n", + "\n", + " On the **Expression Cache** tab, define additional convergence criteria for self\n", + " impedance of the four coil ports." + ] + }, + { + "cell_type": "markdown", + "id": "25d1dc64", + "metadata": {}, + "source": [ + "Set each of these convergence criteria to 2.5 ohm.\n", + "This example limits the number of passes to two to reduce simulation time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bc96579", + "metadata": {}, + "outputs": [], + "source": [ + "im_traces = hfss.get_traces_for_plot(\n", + " get_mutual_terms=False, category=\"im(Z\", first_element_filter=\"Coil1_p*\"\n", + ")\n", + "\n", + "hfss.setups[0].enable_expression_cache(\n", + " report_type=\"Modal Solution Data\",\n", + " expressions=im_traces,\n", + " isconvergence=True,\n", + " isrelativeconvergence=False,\n", + " conv_criteria=2.5,\n", + " use_cache_for_freq=False,\n", + ")\n", + "hfss.setups[0].props[\"MaximumPasses\"] = 1" + ] + }, + { + "cell_type": "markdown", + "id": "7c0f7e5f", + "metadata": {}, + "source": [ + "## Edit sources\n", + "\n", + "The 3D component of the MRI coil contains all the ports,\n", + "but the sources for these ports are not yet defined.\n", + "Browse to and select the ``sources.csv`` file.\n", + "The sources in this file were determined by tuning the coil at 63.8 MHz.\n", + "Notice that ``input_scale`` is a multiplier that lets you quickly adjust the coil excitation power." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19fa16e5", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.edit_sources_from_file(os.path.join(project_path, \"sources.csv\"))" + ] + }, + { + "cell_type": "markdown", + "id": "f2e6c149", + "metadata": {}, + "source": [ + "## Run simulation\n", + "\n", + "Save and analyze the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0694fcd5", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project(file_name=os.path.join(project_path, \"solved.aedt\"))\n", + "hfss.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "166af60f", + "metadata": {}, + "source": [ + "## Plot SAR on cut plane in phantom\n", + "\n", + "Ensure that the SAR averaging method is set to ``Gridless``.\n", + "Plot ``Average_SAR`` on the global YZ plane.\n", + "Draw ``Point1`` at the origin of the implant coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a63459f7", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.sar_setup(\n", + " assignment=-1,\n", + " average_sar_method=1,\n", + " tissue_mass=1,\n", + " material_density=1,\n", + ")\n", + "hfss.post.create_fieldplot_cutplane(\n", + " assignment=[\"implant:YZ\"], quantity=\"Average_SAR\", filter_objects=[\"implant_box\"]\n", + ")\n", + "\n", + "hfss.modeler.set_working_coordinate_system(\"implant\")\n", + "hfss.modeler.create_point(position=[0, 0, 0], name=\"Point1\")\n", + "\n", + "plot = hfss.post.plot_field(\n", + " quantity=\"Average_SAR\",\n", + " assignment=\"implant:YZ\",\n", + " plot_type=\"CutPlane\",\n", + " show_legend=False,\n", + " filter_objects=[\"implant_box\"],\n", + " export_path=hfss.working_directory,\n", + " show=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e0d0c830", + "metadata": {}, + "source": [ + "## Adjust input Power to MRI coil\n", + "\n", + "Adjust the MRI coil’s input power so that the average SAR at ``Point1`` is 1 W/kg.\n", + "Note that the SAR and input power are linearly related.\n", + "\n", + "To determine therequired input, calculate\n", + "``input_scale = 1/AverageSAR`` at ``Point1``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da6e24b1", + "metadata": {}, + "outputs": [], + "source": [ + "sol_data = hfss.post.get_solution_data(\n", + " expressions=\"Average_SAR\",\n", + " primary_sweep_variable=\"Freq\",\n", + " context=\"Point1\",\n", + " report_category=\"Fields\",\n", + ")\n", + "sol_data.data_real()\n", + "\n", + "hfss[\"input_scale\"] = 1 / sol_data.data_real()[0]" + ] + }, + { + "cell_type": "markdown", + "id": "2f4c81ef", + "metadata": {}, + "source": [ + "## Analyze phantom with implant\n", + "\n", + "Import the implant geometry.\n", + "Subtract the rod from the implant box.\n", + "Assign titanium to the imported object rod.\n", + "Analyze the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ef11a84", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.import_3d_cad(os.path.join(project_path, \"implant_rod.sat\"))\n", + "\n", + "hfss.modeler[\"implant_box\"].subtract(tool_list=\"rod\", keep_originals=True)\n", + "hfss.modeler[\"rod\"].material_name = \"titanium\"\n", + "hfss.analyze(cores=NUM_CORES)\n", + "hfss.save_project()" + ] + }, + { + "cell_type": "markdown", + "id": "55cb2478", + "metadata": {}, + "source": [ + "## Run a thermal simulation\n", + "\n", + "Initialize a new Mechanical transient thermal analysis.\n", + "This type of analysis is available in AEDT in 2023 R2 and later as a beta feature." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45f61197", + "metadata": {}, + "outputs": [], + "source": [ + "mech = Mechanical(solution_type=\"Transient Thermal\", version=AEDT_VERSION)" + ] + }, + { + "cell_type": "markdown", + "id": "170f1fdd", + "metadata": {}, + "source": [ + "## Copy geometries\n", + "\n", + "Copy bodies from the HFSS project. The 3D component is not copied." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9502fc9f", + "metadata": {}, + "outputs": [], + "source": [ + "mech.copy_solid_bodies_from(hfss)" + ] + }, + { + "cell_type": "markdown", + "id": "150628ff", + "metadata": {}, + "source": [ + "## Link sources to EM losses\n", + "\n", + "Link sources to the EM losses.\n", + "Assign external convection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ba82bd7", + "metadata": {}, + "outputs": [], + "source": [ + "exc = mech.assign_em_losses(\n", + " design=hfss.design_name,\n", + " setup=hfss.setups[0].name,\n", + " sweep=\"LastAdaptive\",\n", + " map_frequency=hfss.setups[0].props[\"Frequency\"],\n", + " surface_objects=mech.get_all_conductors_names(),\n", + ")\n", + "mech.assign_uniform_convection(\n", + " assignment=mech.modeler[\"Region\"].faces, convection_value=1\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9e0e1ae1", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup and edit properties." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edd0245a", + "metadata": {}, + "outputs": [], + "source": [ + "setup = mech.create_setup()\n", + "# setup.add_mesh_link(\"backgroundSAR\")\n", + "# mech.create_dataset1d_design(\"PowerMap\", [0, 239, 240, 360], [1, 1, 0, 0])\n", + "# exc.props[\"LossMultiplier\"] = \"pwl(PowerMap,Time)\"\n", + "\n", + "mech.modeler.set_working_coordinate_system(\"implant\")\n", + "mech.modeler.create_point(position=[0, 0, 0], name=\"Point1\")\n", + "setup.props[\"Stop Time\"] = 30\n", + "setup.props[\"Time Step\"] = \"10s\"\n", + "setup.props[\"SaveFieldsType\"] = \"Every N Steps\"\n", + "setup.props[\"N Steps\"] = \"2\"" + ] + }, + { + "cell_type": "markdown", + "id": "420e94d3", + "metadata": {}, + "source": [ + "## Analyze project\n", + "\n", + "Analyze the Mechanical project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08a8b299", + "metadata": {}, + "outputs": [], + "source": [ + "mech.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "49a9320c", + "metadata": {}, + "source": [ + "## Plot fields\n", + "\n", + "Plot the temperature on cut plane.\n", + "Plot the temperature on the point." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "479aa532", + "metadata": {}, + "outputs": [], + "source": [ + "mech.post.create_fieldplot_cutplane(\n", + " assignment=[\"implant:YZ\"],\n", + " quantity=\"Temperature\",\n", + " filter_objects=[\"implant_box\"],\n", + " intrinsics={\"Time\": \"10s\"},\n", + ")\n", + "mech.save_project()\n", + "\n", + "data = mech.post.get_solution_data(\n", + " expressions=\"Temperature\",\n", + " primary_sweep_variable=\"Time\",\n", + " context=\"Point1\",\n", + " report_category=\"Fields\",\n", + ")\n", + "data.plot()\n", + "\n", + "mech.post.plot_animated_field(\n", + " quantity=\"Temperature\",\n", + " assignment=\"implant:YZ\",\n", + " plot_type=\"CutPlane\",\n", + " intrinsics={\"Time\": \"10s\"},\n", + " variation_variable=\"Time\",\n", + " variations=[\"10s\", \"30s\"],\n", + " filter_objects=[\"implant_box\"],\n", + " show=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b469a0df", + "metadata": {}, + "source": [ + "## Run a new thermal simulation\n", + "\n", + "Initialize a new Icepak transient thermal analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d38db35", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = Icepak(solution_type=\"Transient\", version=AEDT_VERSION)\n", + "ipk.design_solutions.problem_type = \"TemperatureOnly\"" + ] + }, + { + "cell_type": "markdown", + "id": "02814631", + "metadata": {}, + "source": [ + "## Copy geometries\n", + "\n", + "Copy bodies from the HFSS project. The 3D component is not copied." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e5392db", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler.delete(\"Region\")\n", + "ipk.copy_solid_bodies_from(hfss)" + ] + }, + { + "cell_type": "markdown", + "id": "6d41c30b", + "metadata": {}, + "source": [ + "## Link sources to EM losses\n", + "\n", + "Link sources to the EM losses.\n", + "Assign external convection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f603a88", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assign_em_losses(\n", + " design=hfss.design_name,\n", + " setup=hfss.setups[0].name,\n", + " sweep=\"LastAdaptive\",\n", + " map_frequency=hfss.setups[0].props[\"Frequency\"],\n", + " surface_objects=ipk.get_all_conductors_names(),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1ec0af30", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup and edit properties.\n", + "Simulation takes 30 seconds." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62a93de6", + "metadata": {}, + "outputs": [], + "source": [ + "setup = ipk.create_setup()\n", + "\n", + "setup.props[\"Stop Time\"] = 30\n", + "setup.props[\"N Steps\"] = 2\n", + "setup.props[\"Time Step\"] = 5\n", + "setup.props[\"Convergence Criteria - Energy\"] = 1e-12" + ] + }, + { + "cell_type": "markdown", + "id": "68fff113", + "metadata": {}, + "source": [ + "## Create mesh region\n", + "\n", + "Create a mesh region and change the accuracy level to 4." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ce80f25", + "metadata": {}, + "outputs": [], + "source": [ + "bound = ipk.modeler[\"implant_box\"].bounding_box\n", + "mesh_box = ipk.modeler.create_box(\n", + " origin=bound[:3],\n", + " sizes=[bound[3] - bound[0], bound[4] - bound[1], bound[5] - bound[2]],\n", + ")\n", + "mesh_box.model = False\n", + "mesh_region = ipk.mesh.assign_mesh_region([mesh_box.name])\n", + "mesh_region.UserSpecifiedSettings = False\n", + "mesh_region.Level = 4\n", + "mesh_region.update()" + ] + }, + { + "cell_type": "markdown", + "id": "1db82a38", + "metadata": {}, + "source": [ + "## Create point monitor\n", + "\n", + "Create a point monitor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c64c60e9", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.modeler.set_working_coordinate_system(\"implant\")\n", + "ipk.monitor.assign_point_monitor(point_position=[0, 0, 0], monitor_name=\"Point1\")\n", + "ipk.assign_openings(ipk.modeler[\"Region\"].top_face_z)\n", + "# -" + ] + }, + { + "cell_type": "markdown", + "id": "2ca22697", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a219f37", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "6bd0e04e", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc2e913f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/coplanar_waveguide.ipynb.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/coplanar_waveguide.ipynb.txt new file mode 100644 index 00000000..5a4862bd --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/coplanar_waveguide.ipynb.txt @@ -0,0 +1,513 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c73676b5", + "metadata": {}, + "source": [ + "# CPWG analysis" + ] + }, + { + "cell_type": "markdown", + "id": "d3a87cc9", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a CPWG (coplanar waveguide with ground) design\n", + "in 2D Extractor and run a simulation.\n", + "\n", + "Keywords: **Q2D**, **CPWG**." + ] + }, + { + "cell_type": "markdown", + "id": "e62aac9a", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74b86ab4", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22819d9e", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "5842c989", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66e246de", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Run the example without opening the UI." + ] + }, + { + "cell_type": "markdown", + "id": "93622893", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b8af693", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "861c8bc1", + "metadata": {}, + "source": [ + "## Launch AEDT and 2D Extractor\n", + "\n", + "Launch AEDT 2024.2 in graphical mode and launch 2D Extractor. This example\n", + "uses SI units." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22ef0c0c", + "metadata": {}, + "outputs": [], + "source": [ + "q2d = ansys.aedt.core.Q2d(\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " project=os.path.join(temp_folder.name, \"cpwg\"),\n", + " design=\"coplanar_waveguide\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "15ed19b2", + "metadata": {}, + "source": [ + "## Create model\n", + "\n", + "Define variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb2ccda0", + "metadata": {}, + "outputs": [], + "source": [ + "e_factor = \"e_factor\"\n", + "sig_bot_w = \"sig_bot_w\"\n", + "co_gnd_w = \"gnd_w\"\n", + "clearance = \"clearance\"\n", + "cond_h = \"cond_h\"\n", + "d_h = \"d_h\"\n", + "sm_h = \"sm_h\"\n", + "\n", + "for var_name, var_value in {\n", + " \"sig_bot_w\": \"150um\",\n", + " \"e_factor\": \"2\",\n", + " \"gnd_w\": \"500um\",\n", + " \"clearance\": \"150um\",\n", + " \"cond_h\": \"50um\",\n", + " \"d_h\": \"150um\",\n", + " \"sm_h\": \"20um\",\n", + "}.items():\n", + " q2d[var_name] = var_value\n", + "\n", + "delta_w_half = \"({0}/{1})\".format(cond_h, e_factor)\n", + "sig_top_w = \"({1}-{0}*2)\".format(delta_w_half, sig_bot_w)\n", + "co_gnd_top_w = \"({1}-{0}*2)\".format(delta_w_half, co_gnd_w)\n", + "model_w = \"{}*2+{}*2+{}\".format(co_gnd_w, clearance, sig_bot_w)" + ] + }, + { + "cell_type": "markdown", + "id": "85d609f9", + "metadata": {}, + "source": [ + "Create primitives and define the layer heights." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12464d8a", + "metadata": {}, + "outputs": [], + "source": [ + "layer_1_lh = 0\n", + "layer_1_uh = cond_h\n", + "layer_2_lh = layer_1_uh + \"+\" + d_h\n", + "layer_2_uh = layer_2_lh + \"+\" + cond_h" + ] + }, + { + "cell_type": "markdown", + "id": "9e5053e3", + "metadata": {}, + "source": [ + "Create a signal conductor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58c48917", + "metadata": {}, + "outputs": [], + "source": [ + "base_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_lh, 0], [sig_bot_w, layer_2_lh, 0]], name=\"signal\"\n", + ")\n", + "top_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_uh, 0], [sig_top_w, layer_2_uh, 0]]\n", + ")\n", + "q2d.modeler.move(assignment=[top_line_obj], vector=[delta_w_half, 0, 0])\n", + "q2d.modeler.connect([base_line_obj, top_line_obj])\n", + "q2d.modeler.move(\n", + " assignment=[base_line_obj], vector=[\"{}+{}\".format(co_gnd_w, clearance), 0, 0]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8ceb3f4f", + "metadata": {}, + "source": [ + "Create a coplanar ground." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e6a74ed", + "metadata": {}, + "outputs": [], + "source": [ + "base_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_lh, 0], [co_gnd_w, layer_2_lh, 0]], name=\"co_gnd_left\"\n", + ")\n", + "top_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_uh, 0], [co_gnd_top_w, layer_2_uh, 0]]\n", + ")\n", + "q2d.modeler.move(objid=[top_line_obj], vector=[delta_w_half, 0, 0])\n", + "q2d.modeler.connect([base_line_obj, top_line_obj])\n", + "\n", + "base_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_lh, 0], [co_gnd_w, layer_2_lh, 0]], name=\"co_gnd_right\"\n", + ")\n", + "top_line_obj = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_uh, 0], [co_gnd_top_w, layer_2_uh, 0]]\n", + ")\n", + "q2d.modeler.move(objid=[top_line_obj], vector=[delta_w_half, 0, 0])\n", + "q2d.modeler.connect([base_line_obj, top_line_obj])\n", + "q2d.modeler.move(\n", + " assignment=[base_line_obj],\n", + " vector=[\"{}+{}*2+{}\".format(co_gnd_w, clearance, sig_bot_w), 0, 0],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0bf539a1", + "metadata": {}, + "source": [ + "Create a reference ground plane." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0af18ac5", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.create_rectangle(\n", + " origin=[0, layer_1_lh, 0], sizes=[model_w, cond_h], name=\"ref_gnd\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "eb0f5b4f", + "metadata": {}, + "source": [ + "Define the substrate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55aba4dd", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.create_rectangle(\n", + " position=[0, layer_1_uh, 0],\n", + " dimension_list=[model_w, d_h],\n", + " name=\"Dielectric\",\n", + " matname=\"FR4_epoxy\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b0dd4040", + "metadata": {}, + "source": [ + "Assign a conformal coating." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c51f100", + "metadata": {}, + "outputs": [], + "source": [ + "sm_obj_list = []\n", + "ids = [1, 2, 3]\n", + "if AEDT_VERSION >= \"2023.1\":\n", + " ids = [0, 1, 2]\n", + "\n", + "for obj_name in [\"signal\", \"co_gnd_left\", \"co_gnd_right\"]:\n", + " obj = q2d.modeler.get_object_from_name(obj_name)\n", + " e_obj_list = []\n", + " for i in ids:\n", + " e_obj = q2d.modeler.create_object_from_edge(obj.edges[i])\n", + " e_obj_list.append(e_obj)\n", + " e_obj_1 = e_obj_list[0]\n", + " q2d.modeler.unite(e_obj_list)\n", + " new_obj = q2d.modeler.sweep_along_vector(\n", + " assignment=e_obj_1.id, sweep_vector=[0, sm_h, 0]\n", + " )\n", + " sm_obj_list.append(e_obj_1)\n", + "\n", + "new_obj = q2d.modeler.create_rectangle(\n", + " origin=[co_gnd_w, layer_2_lh, 0], sizes=[clearance, sm_h]\n", + ")\n", + "sm_obj_list.append(new_obj)\n", + "\n", + "new_obj = q2d.modeler.create_rectangle(\n", + " origin=[co_gnd_w, layer_2_lh, 0], sizes=[clearance, sm_h]\n", + ")\n", + "q2d.modeler.move(assignment=[new_obj], vector=[sig_bot_w + \"+\" + clearance, 0, 0])\n", + "sm_obj_list.append(new_obj)\n", + "\n", + "sm_obj = sm_obj_list[0]\n", + "q2d.modeler.unite(sm_obj_list)\n", + "sm_obj.material_name = \"SolderMask\"\n", + "sm_obj.color = (0, 150, 100)\n", + "sm_obj.name = \"solder_mask\"" + ] + }, + { + "cell_type": "markdown", + "id": "2d31cd81", + "metadata": {}, + "source": [ + "Assign a conductor to the signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "751a5b24", + "metadata": {}, + "outputs": [], + "source": [ + "obj = q2d.modeler.get_object_from_name(\"signal\")\n", + "q2d.assign_single_conductor(\n", + " name=obj.name,\n", + " assignment=[obj],\n", + " conductor_type=\"SignalLine\",\n", + " solve_option=\"SolveOnBoundary\",\n", + " units=\"mm\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a207e79f", + "metadata": {}, + "source": [ + "Assign the reference ground." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aeeef804", + "metadata": {}, + "outputs": [], + "source": [ + "obj = [\n", + " q2d.modeler.get_object_from_name(i)\n", + " for i in [\"co_gnd_left\", \"co_gnd_right\", \"ref_gnd\"]\n", + "]\n", + "q2d.assign_single_conductor(\n", + " name=\"gnd\",\n", + " assignment=obj,\n", + " conductor_type=\"ReferenceGround\",\n", + " solve_option=\"SolveOnBoundary\",\n", + " units=\"mm\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d7f74d82", + "metadata": {}, + "source": [ + "Assign the Huray model for conductive losses on the signal trace." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1abd463", + "metadata": {}, + "outputs": [], + "source": [ + "obj = q2d.modeler.get_object_from_name(\"signal\")\n", + "q2d.assign_huray_finitecond_to_edges(\n", + " obj.edges, radius=\"0.5um\", ratio=3, name=\"b_\" + obj.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9dd04546", + "metadata": {}, + "source": [ + "## Create the simulation setup\n", + "\n", + "Create the setup, analyze it, and plot solution data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4449478", + "metadata": {}, + "outputs": [], + "source": [ + "setup = q2d.create_setup(setupname=\"new_setup\")\n", + "\n", + "sweep = setup.add_sweep(name=\"sweep1\", sweep_type=\"Discrete\")\n", + "sweep.props[\"RangeType\"] = \"LinearStep\"\n", + "sweep.props[\"RangeStart\"] = \"1GHz\"\n", + "sweep.props[\"RangeStep\"] = \"100MHz\"\n", + "sweep.props[\"RangeEnd\"] = \"5GHz\"\n", + "sweep.props[\"SaveFields\"] = False\n", + "sweep.props[\"SaveRadFields\"] = False\n", + "sweep.props[\"Type\"] = \"Interpolating\"\n", + "\n", + "sweep.update()\n", + "\n", + "q2d.analyze(cores=NUM_CORES)\n", + "\n", + "data = q2d.post.get_solution_data(expressions=\"Z0(signal,signal)\", context=\"Original\")\n", + "data.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "d73e70b6", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd024e34", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.save_project()\n", + "q2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e09110d4", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44d5fd1b", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/index.rst.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/index.rst.txt new file mode 100644 index 00000000..657650a4 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/index.rst.txt @@ -0,0 +1,140 @@ +Radio frequency and millimeter wave +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These examples use PyAEDT to show some radio frequency and millimeter wave applications. + + +.. grid:: 2 + + .. grid-item-card:: Inductive iris waveguide filter + :padding: 2 2 2 2 + :link: iris_filter + :link-type: doc + + .. image:: _static/wgf.png + :alt: Waveguide filter + :width: 250px + :height: 200px + :align: center + + This example shows how to build and analyze a four-pole X-Band waveguide filter using inductive irises. + + .. grid-item-card:: Spiral inductor + :padding: 2 2 2 2 + :link: spiral + :link-type: doc + + .. image:: _static/spiral.png + :alt: Spiral + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a spiral inductor, solve it, and plot results. + + .. grid-item-card:: CPWG analysis + :padding: 2 2 2 2 + :link: coplanar_waveguide + :link-type: doc + + .. image:: _static/cpwg.png + :alt: CPWG + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a CPWG (coplanar waveguide with ground) design in 2D Extractor and run a simulation. + + + .. grid-item-card:: Stripline analysis + :padding: 2 2 2 2 + :link: stripline + :link-type: doc + + .. image:: _static/stripline.png + :alt: Stripline + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a differential stripline design in 2D Extractor and run a simulation. + + .. grid-item-card:: Lumped element filter design + :padding: 2 2 2 2 + :link: lumped_element + :link-type: doc + + .. image:: _static/lumped_filter.png + :alt: Lumped element filter + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to use the FilterSolutions module to design and visualize the frequency + response of a band-pass Butterworth filter. + + + .. grid-item-card:: Flex cable CPWG + :padding: 2 2 2 2 + :link: ../emc/flex_cable + :link-type: doc + + .. image:: ../emc/_static/flex_cable.png + :alt: Flex cable + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a flex cable CPWG (coplanar waveguide with ground). + + .. grid-item-card:: Eigenmode filter + :padding: 2 2 2 2 + :link: ../emc/eigenmode + :link-type: doc + + .. image:: ../emc/_static/eigenmode.png + :alt: Eigenmode + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to automate the Eigenmode solver in HFSS. + + .. grid-item-card:: FSS unit cell simulation + :padding: 2 2 2 2 + :link: ../antenna/fss_unitcell + :link-type: doc + + .. image:: ../antenna/_static/unitcell.png + :alt: FSS + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to model and simulate a unit cell for a frequency-selective surface in HFSS. + + .. grid-item-card:: RF interference + :padding: 2 2 2 2 + :link: ../antenna/interferences/index + :link-type: doc + + .. image:: ../antenna/interferences/_static/emit_simple_cosite.png + :alt: EMIT logo + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some general capabilities of EMIT for RF interference. + + .. toctree:: + :hidden: + + iris_filter + spiral + coplanar_waveguide + stripline + lumped_element + ../emc/flex_cable + ../emc/eigenmode + ../antenna/fss_unitcell + ../antenna/interferences/index diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/iris_filter.ipynb.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/iris_filter.ipynb.txt new file mode 100644 index 00000000..819f5051 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/iris_filter.ipynb.txt @@ -0,0 +1,555 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f76aecda", + "metadata": {}, + "source": [ + "# Inductive iris waveguide filter\n", + "\n", + "This example shows how to build and analyze a four-pole\n", + "X-Band waveguide filter using inductive irises.\n", + "\n", + "Keywords: **HFSS**, **modal**, **waveguide filter**." + ] + }, + { + "cell_type": "markdown", + "id": "634d1c78", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "id": "e66379ae", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41b1a55e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6ca0e70", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "5ed851c6", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9c94ff2", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "104f9ff1", + "metadata": {}, + "source": [ + "## Launch AEDT" + ] + }, + { + "cell_type": "markdown", + "id": "a8de4afa", + "metadata": {}, + "source": [ + "### Define parameters and values for waveguide iris filter\n", + "\n", + "Define these parameters:" + ] + }, + { + "cell_type": "markdown", + "id": "e74e6408", + "metadata": {}, + "source": [ + "l: Length of the cavity from the mid-point of one iris\n", + " to the midpoint of the next iris\n", + "\n", + "w: Width of the iris opening\n", + "\n", + "a: Long dimension of the waveguide cross-section (X-Band)\n", + "\n", + "b: Short dimension of the waveguide cross-section\n", + "\n", + "t: Metal thickness of the iris insert" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "086ae251", + "metadata": {}, + "outputs": [], + "source": [ + "wgparams = {\n", + " \"l\": [0.7428, 0.82188],\n", + " \"w\": [0.50013, 0.3642, 0.3458],\n", + " \"a\": 0.4,\n", + " \"b\": 0.9,\n", + " \"t\": 0.15,\n", + " \"units\": \"in\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "b16ccff9", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74991f46", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "9971446e", + "metadata": {}, + "source": [ + "### Create HFSS design" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b04799f4", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"waveguide.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " design=\"filter\",\n", + " solution_type=\"Modal\",\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " close_on_exit=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "75105c78", + "metadata": {}, + "source": [ + "### Initialize design parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a40c5d50", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.model_units = \"in\" # Set to inches\n", + "var_mapping = dict() # Used by parse_expr to parse expressions.\n", + "for key in wgparams:\n", + " if type(wgparams[key]) in [int, float]:\n", + " hfss[key] = str(wgparams[key]) + wgparams[\"units\"]\n", + " var_mapping[key] = wgparams[key] # Used for expression parsing.\n", + " elif type(wgparams[key]) == list:\n", + " count = 1\n", + " for v in wgparams[key]:\n", + " this_key = key + str(count)\n", + " hfss[this_key] = str(v) + wgparams[\"units\"]\n", + " var_mapping[\n", + " this_key\n", + " ] = v # Used to parse expressions and generate numerical values.\n", + " count += 1\n", + "\n", + "if len(wgparams[\"l\"]) % 2 == 0:\n", + " zstart = \"-t/2\" # Even number of cavities, odd number of irises.\n", + " is_even = True\n", + "else:\n", + " zstart = \"l1/2 - t/2\" # Odd number of cavities, even number of irises.\n", + " is_even = False" + ] + }, + { + "cell_type": "markdown", + "id": "120a62d6", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "### Draw parametric waveguide filter\n", + "\n", + "Define a function to place each iris at the correct longitudinal (z) position,\n", + "Loop from the largest index (interior of the filter) to 1, which is the first\n", + "iris nearest the waveguide ports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28d571d7", + "metadata": {}, + "outputs": [], + "source": [ + "def place_iris(z_pos, dz, param_count):\n", + " w_str = \"w\" + str(param_count) # Iris width parameter as a string.\n", + " this_name = \"iris_a_\" + str(param_count) # Iris object name in the HFSS project.\n", + " iris_new = [] # Return a list of the two objects that make up the iris.\n", + " if this_name in hfss.modeler.object_names:\n", + " this_name = this_name.replace(\"a\", \"c\")\n", + " iris_new.append(\n", + " hfss.modeler.create_box(\n", + " [\"-b/2\", \"-a/2\", z_pos],\n", + " [\"(b - \" + w_str + \")/2\", \"a\", dz],\n", + " name=this_name,\n", + " material=\"silver\",\n", + " )\n", + " )\n", + " iris_new.append(iris_new[0].mirror([0, 0, 0], [1, 0, 0], duplicate=True))\n", + " return iris_new" + ] + }, + { + "cell_type": "markdown", + "id": "eb572e0d", + "metadata": {}, + "source": [ + "### Place irises\n", + "\n", + "Place the irises from inner (highest integer) to outer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "374870cd", + "metadata": {}, + "outputs": [], + "source": [ + "zpos = zstart\n", + "for count in reversed(range(1, len(wgparams[\"w\"]) + 1)):\n", + " if count < len(wgparams[\"w\"]): # Update zpos\n", + " zpos = zpos + \"\".join([\" + l\" + str(count) + \" + \"])[:-3]\n", + " iris = place_iris(zpos, \"t\", count)\n", + " iris = place_iris(\"-(\" + zpos + \")\", \"-t\", count)\n", + "\n", + " else: # Place first iris\n", + " iris = place_iris(zpos, \"t\", count)\n", + " if not is_even:\n", + " iris = place_iris(\"-(\" + zpos + \")\", \"-t\", count)" + ] + }, + { + "cell_type": "markdown", + "id": "85292925", + "metadata": {}, + "source": [ + "### Draw full waveguide with ports\n", + "\n", + "Use ``hfss.variable_manager``, which acts like a dictionary, to return an instance of\n", + "the ``ansys.aedt.core.application.variables.VariableManager`` class for any variable.\n", + "The ``VariableManager`` instance takes the HFSS variable name as a key.\n", + "``VariableManager`` properties enable access to update, modify, and\n", + "evaluate variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "059c8ad5", + "metadata": {}, + "outputs": [], + "source": [ + "var_mapping[\"port_extension\"] = 1.5 * wgparams[\"l\"][0]\n", + "hfss[\"port_extension\"] = str(var_mapping[\"port_extension\"]) + wgparams[\"units\"]\n", + "hfss[\"wg_z_start\"] = \"-(\" + zpos + \") - port_extension\"\n", + "hfss[\"wg_length\"] = \"2*(\" + zpos + \" + port_extension )\"\n", + "wg_z_start = hfss.variable_manager[\"wg_z_start\"]\n", + "wg_length = hfss.variable_manager[\"wg_length\"]\n", + "hfss[\"u_start\"] = \"-a/2\"\n", + "hfss[\"u_end\"] = \"a/2\"\n", + "hfss.modeler.create_box(\n", + " [\"-b/2\", \"-a/2\", \"wg_z_start\"],\n", + " [\"b\", \"a\", \"wg_length\"],\n", + " name=\"waveguide\",\n", + " material=\"vacuum\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c9f6d500", + "metadata": {}, + "source": [ + "### Draw the entire waveguide\n", + "\n", + "The variable ``# wg_z`` is the total length of the waveguide, including the port extension.\n", + "Note that the ``.evaluated_value`` provides access to the numerical value of\n", + "``wg_z_start``, which is an expression in HFSS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68bc375d", + "metadata": {}, + "outputs": [], + "source": [ + "wg_z = [\n", + " wg_z_start.evaluated_value,\n", + " hfss.value_with_units(wg_z_start.numeric_value + wg_length.numeric_value, \"in\"),\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "3eb7369e", + "metadata": {}, + "source": [ + "Assign wave ports to the end faces of the waveguide\n", + "and define the calibration lines to ensure self-consistent\n", + "polarization between wave ports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c450d65e", + "metadata": {}, + "outputs": [], + "source": [ + "count = 0\n", + "ports = []\n", + "for n, z in enumerate(wg_z):\n", + " face_id = hfss.modeler.get_faceid_from_position([0, 0, z], assignment=\"waveguide\")\n", + " u_start = [0, hfss.variable_manager[\"u_start\"].evaluated_value, z]\n", + " u_end = [0, hfss.variable_manager[\"u_end\"].evaluated_value, z]\n", + "\n", + " ports.append(\n", + " hfss.wave_port(\n", + " face_id,\n", + " integration_line=[u_start, u_end],\n", + " name=\"P\" + str(n + 1),\n", + " renormalize=False,\n", + " )\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "9989f68b", + "metadata": {}, + "source": [ + "### Insert mesh adaptation setup\n", + "\n", + "Insert a mesh adaptation setup using refinement at two frequencies.\n", + "This approach is useful for resonant structures because the coarse initial\n", + "mesh impacts the resonant frequency and, hence, the field propagation through the\n", + "filter. Adaptation at multiple frequencies helps to ensure that energy propagates\n", + "through the resonant structure while the mesh is refined." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7c1ffe5", + "metadata": {}, + "outputs": [], + "source": [ + "setup = hfss.create_setup(\n", + " \"Setup1\",\n", + " setup_type=\"HFSSDriven\",\n", + " MultipleAdaptiveFreqsSetup=[\"9.8GHz\", \"10.2GHz\"],\n", + " MaximumPasses=5,\n", + ")\n", + "\n", + "setup.create_frequency_sweep(\n", + " unit=\"GHz\",\n", + " name=\"Sweep1\",\n", + " start_frequency=9.5,\n", + " stop_frequency=10.5,\n", + " sweep_type=\"Interpolating\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "60cc9978", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + " Solve the project with two tasks.\n", + " Each frequency point is solved simultaneously." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e571292", + "metadata": {}, + "outputs": [], + "source": [ + "setup.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "e2af1345", + "metadata": {}, + "source": [ + "### Postprocess\n", + "\n", + " The following commands fetch solution data from HFSS for plotting directly\n", + " from the Python interpreter.\n", + "\n", + " **Caution:** The syntax for expressions must be identical to that used\n", + " in HFSS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac4e215c", + "metadata": {}, + "outputs": [], + "source": [ + "traces_to_plot = hfss.get_traces_for_plot(second_element_filter=\"P1*\")\n", + "report = hfss.post.create_report(traces_to_plot) # Creates a report in HFSS\n", + "solution = report.get_solution_data()\n", + "\n", + "plt = solution.plot(solution.expressions) # Matplotlib axes object." + ] + }, + { + "cell_type": "markdown", + "id": "895e445f", + "metadata": {}, + "source": [ + " The following command generates a field plot in HFSS and uses PyVista\n", + " to plot the field in Jupyter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e38220c7", + "metadata": {}, + "outputs": [], + "source": [ + "plot = hfss.post.plot_field(\n", + " quantity=\"Mag_E\",\n", + " assignment=[\"Global:XZ\"],\n", + " plot_type=\"CutPlane\",\n", + " setup=hfss.nominal_adaptive,\n", + " intrinsics={\"Freq\": \"9.8GHz\", \"Phase\": \"0deg\"},\n", + " export_path=hfss.working_directory,\n", + " show=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ad947086", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + " The following command saves the project to a file and closes AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3fc95d94", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "d0956c3a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85e08596", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/lumped_element.ipynb.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/lumped_element.ipynb.txt new file mode 100644 index 00000000..28980bec --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/lumped_element.ipynb.txt @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5022bd19", + "metadata": {}, + "source": [ + "# Lumped element filter design\n", + "\n", + "This example shows how to use PyAEDT to use the ``FilterSolutions`` module to design and\n", + "visualize the frequency response of a band-pass Butterworth filter.\n", + "\n", + "Keywords: **filter solutions**" + ] + }, + { + "cell_type": "markdown", + "id": "52ac84ce", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3401148d", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import matplotlib.pyplot as plt\n", + "from ansys.aedt.core.filtersolutions_core.attributes import (\n", + " FilterClass, FilterImplementation, FilterType)\n", + "from ansys.aedt.core.filtersolutions_core.ideal_response import \\\n", + " FrequencyResponseColumn" + ] + }, + { + "cell_type": "markdown", + "id": "e1a0ec1c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "900b4689", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2025.1\"" + ] + }, + { + "cell_type": "markdown", + "id": "15298ece", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Define function used for plotting\n", + "\n", + "Define formal plot function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "deccb10d", + "metadata": {}, + "outputs": [], + "source": [ + "def format_plot():\n", + " plt.xlabel(\"Frequency (Hz)\")\n", + " plt.ylabel(\"Magnitude S21 (dB)\")\n", + " plt.title(\"Ideal Frequency Response\")\n", + " plt.xscale(\"log\")\n", + " plt.legend()\n", + " plt.grid()" + ] + }, + { + "cell_type": "markdown", + "id": "fe92108a", + "metadata": {}, + "source": [ + "## Create lumped filter design\n", + "\n", + "Create a lumped element filter design and assign the class, type, frequency, and order." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5b0e69b", + "metadata": {}, + "outputs": [], + "source": [ + "design = ansys.aedt.core.FilterSolutions(\n", + " version=AEDT_VERSION, implementation_type=FilterImplementation.LUMPED\n", + ")\n", + "design.attributes.filter_class = FilterClass.BAND_PASS\n", + "design.attributes.filter_type = FilterType.BUTTERWORTH\n", + "design.attributes.pass_band_center_frequency = \"1G\"\n", + "design.attributes.pass_band_width_frequency = \"500M\"\n", + "design.attributes.filter_order = 5" + ] + }, + { + "cell_type": "markdown", + "id": "4178b617", + "metadata": {}, + "source": [ + "## Plot frequency response of filter\n", + "\n", + "Plot the frequency response of the filter without any transmission zeros." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "540c6128", + "metadata": {}, + "outputs": [], + "source": [ + "freq, mag_db = design.ideal_response.frequency_response(\n", + " FrequencyResponseColumn.MAGNITUDE_DB\n", + ")\n", + "plt.plot(freq, mag_db, linewidth=2.0, label=\"Without Tx Zero\")\n", + "format_plot()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "91b6a4b0", + "metadata": {}, + "source": [ + "## Add a transmission zero to filter design\n", + "\n", + "Add a transmission zero that yields nulls separated by two times the pass band width (1 GHz).\n", + "Plot the frequency response of the filter with the transmission zero." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f3cb9d3", + "metadata": {}, + "outputs": [], + "source": [ + "design.transmission_zeros_ratio.append_row(\"2.0\")\n", + "freq_with_zero, mag_db_with_zero = design.ideal_response.frequency_response(\n", + " FrequencyResponseColumn.MAGNITUDE_DB\n", + ")\n", + "plt.plot(freq, mag_db, linewidth=2.0, label=\"Without Tx Zero\")\n", + "plt.plot(freq_with_zero, mag_db_with_zero, linewidth=2.0, label=\"With Tx Zero\")\n", + "format_plot()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "4b32f135", + "metadata": {}, + "source": [ + "## Generate netlist for designed filter\n", + "\n", + "Generate and print the netlist for the designed filter with the added transmission zero to\n", + "the filter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1333336", + "metadata": {}, + "outputs": [], + "source": [ + "netlist = design.topology.circuit_response()\n", + "print(\"Netlist: \\n\", netlist)" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/spiral.ipynb.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/spiral.ipynb.txt new file mode 100644 index 00000000..c09645b3 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/spiral.ipynb.txt @@ -0,0 +1,553 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a63bb8ac", + "metadata": {}, + "source": [ + "# Spiral inductor\n", + "\n", + "This example shows how to use PyAEDT to create a spiral inductor, solve it, and plot results.\n", + "\n", + "Keywords: **HFSS**, **spiral**, **inductance**, **output variable**." + ] + }, + { + "cell_type": "markdown", + "id": "0fcd1086", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2307e00c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a66d910d", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "b3ec663c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5da6c936", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "6bc87ca6", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5925ad2c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "e125ee02", + "metadata": {}, + "source": [ + "## Launch HFSS\n", + "\n", + "Create an HFSS design and change the units to microns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f05532c7", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"spiral.aedt\")\n", + "hfss = ansys.aedt.core.Hfss(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " design=\"A1\",\n", + " new_desktop=True,\n", + " solution_type=\"Modal\",\n", + ")\n", + "hfss.modeler.model_units = \"um\"" + ] + }, + { + "cell_type": "markdown", + "id": "e08d22fe", + "metadata": {}, + "source": [ + "## Define variables\n", + "\n", + "Define input variables. You can use the values that follow or edit\n", + "them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b549be5e", + "metadata": {}, + "outputs": [], + "source": [ + "rin = 10\n", + "width = 2\n", + "spacing = 1\n", + "thickness = 1\n", + "Np = 8\n", + "Nr = 10\n", + "gap = 3\n", + "hfss[\"Tsub\"] = \"6\" + hfss.modeler.model_units" + ] + }, + { + "cell_type": "markdown", + "id": "e38a2414", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Standardize polyline\n", + "\n", + "Define a function that creates a polyline using the ``create_line()`` method. This\n", + "function creates a polyline having a fixed width, thickness, and material." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75a64d18", + "metadata": {}, + "outputs": [], + "source": [ + "def create_line(pts):\n", + " hfss.modeler.create_polyline(\n", + " pts,\n", + " xsection_type=\"Rectangle\",\n", + " xsection_width=width,\n", + " xsection_height=thickness,\n", + " material=\"copper\",\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "0cd2e2b4", + "metadata": {}, + "source": [ + "## Create spiral inductor\n", + "\n", + "Create the spiral inductor. This spiral inductor is not\n", + "parametric, but you could parametrize it later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f928363d", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "ind = hfss.modeler.create_spiral(\n", + " internal_radius=rin,\n", + " width=width,\n", + " spacing=spacing,\n", + " turns=Nr,\n", + " faces=Np,\n", + " thickness=thickness,\n", + " material=\"copper\",\n", + " name=\"Inductor1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "91db0152", + "metadata": {}, + "source": [ + "## Center return path\n", + "\n", + "Center the return path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e766d919", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0, z0 = ind.points[0]\n", + "x1, y1, z1 = ind.points[-1]\n", + "create_line([(x0 - width / 2, y0, -gap), (abs(x1) + 5, y0, -gap)])\n", + "hfss.modeler.create_box(\n", + " [x0 - width / 2, y0 - width / 2, -gap - thickness / 2],\n", + " [width, width, gap + thickness],\n", + " matname=\"copper\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b0e20ae1", + "metadata": {}, + "source": [ + "Create port 1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19d09c77", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.create_rectangle(\n", + " orientation=ansys.aedt.core.constants.PLANE.YZ,\n", + " origin=[abs(x1) + 5, y0 - width / 2, -gap - thickness / 2],\n", + " sizes=[width, \"-Tsub+{}{}\".format(gap, hfss.modeler.model_units)],\n", + " name=\"port1\",\n", + ")\n", + "hfss.lumped_port(assignment=\"port1\", integration_line=ansys.aedt.core.constants.AXIS.Z)" + ] + }, + { + "cell_type": "markdown", + "id": "c309d773", + "metadata": {}, + "source": [ + "Create port 2." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40b773f2", + "metadata": {}, + "outputs": [], + "source": [ + "create_line([(x1 + width / 2, y1, 0), (x1 - 5, y1, 0)])\n", + "hfss.modeler.create_rectangle(\n", + " ansys.aedt.core.constants.PLANE.YZ,\n", + " [x1 - 5, y1 - width / 2, -thickness / 2],\n", + " [width, \"-Tsub\"],\n", + " name=\"port2\",\n", + ")\n", + "hfss.lumped_port(assignment=\"port2\", integration_line=ansys.aedt.core.constants.AXIS.Z)" + ] + }, + { + "cell_type": "markdown", + "id": "d6607c36", + "metadata": {}, + "source": [ + "Create the silicon substrate and the ground plane." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f177ad46", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.modeler.create_box(\n", + " [x1 - 20, x1 - 20, \"-Tsub-{}{}/2\".format(thickness, hfss.modeler.model_units)],\n", + " [-2 * x1 + 40, -2 * x1 + 40, \"Tsub\"],\n", + " material=\"silicon\",\n", + ")\n", + "\n", + "hfss.modeler.create_box(\n", + " [x1 - 20, x1 - 20, \"-Tsub-{}{}/2\".format(thickness, hfss.modeler.model_units)],\n", + " [-2 * x1 + 40, -2 * x1 + 40, -0.1],\n", + " material=\"PEC\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "19e0c722", + "metadata": {}, + "source": [ + "## Set up model\n", + "\n", + "Create the air box and radiation boundary condition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3e8f877", + "metadata": {}, + "outputs": [], + "source": [ + "box = hfss.modeler.create_box(\n", + " [\n", + " x1 - 20,\n", + " x1 - 20,\n", + " \"-Tsub-{}{}/2 - 0.1{}\".format(\n", + " thickness, hfss.modeler.model_units, hfss.modeler.model_units\n", + " ),\n", + " ],\n", + " [-2 * x1 + 40, -2 * x1 + 40, 100],\n", + " name=\"airbox\",\n", + " material=\"air\",\n", + ")\n", + "\n", + "hfss.assign_radiation_boundary_to_objects(\"airbox\")" + ] + }, + { + "cell_type": "markdown", + "id": "7738a4b2", + "metadata": {}, + "source": [ + "Assign a material override that allows object intersections,\n", + "assigning conductors higher priority than insulators." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b6d336d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.change_material_override()" + ] + }, + { + "cell_type": "markdown", + "id": "0c628de1", + "metadata": {}, + "source": [ + "View the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6b0e8d3", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.plot(\n", + " show=False,\n", + " output_file=os.path.join(hfss.working_directory, \"Image.jpg\"),\n", + " plot_air_objects=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4ef17dd8", + "metadata": {}, + "source": [ + "## Generate the solution\n", + "\n", + "Create the setup, including a frequency sweep. Then, solve the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "504b6ff9", + "metadata": {}, + "outputs": [], + "source": [ + "setup1 = hfss.create_setup(name=\"setup1\")\n", + "setup1.props[\"Frequency\"] = \"10GHz\"\n", + "hfss.create_linear_count_sweep(\n", + " setup=\"setup1\",\n", + " units=\"GHz\",\n", + " start_frequency=1e-3,\n", + " stop_frequency=50,\n", + " num_of_freq_points=451,\n", + " sweep_type=\"Interpolating\",\n", + ")\n", + "hfss.save_project()\n", + "hfss.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "190e4d5a", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Get report data and use the following formulas to calculate\n", + "the inductance and quality factor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fa9133e", + "metadata": {}, + "outputs": [], + "source": [ + "L_formula = \"1e9*im(1/Y(1,1))/(2*pi*freq)\"\n", + "Q_formula = \"im(Y(1,1))/re(Y(1,1))\"" + ] + }, + { + "cell_type": "markdown", + "id": "df3b2fc4", + "metadata": {}, + "source": [ + "Define the inductance as a postprocessing variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55eeab31", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.create_output_variable(\"L\", L_formula, solution=\"setup1 : LastAdaptive\")" + ] + }, + { + "cell_type": "markdown", + "id": "ec17d361", + "metadata": {}, + "source": [ + "Plot the results using Matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0af3ff02", + "metadata": {}, + "outputs": [], + "source": [ + "data = hfss.post.get_solution_data([L_formula, Q_formula])\n", + "data.plot(\n", + " curves=[L_formula, Q_formula], formula=\"re\", x_label=\"Freq\", y_label=\"L and Q\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "afbd682e", + "metadata": {}, + "source": [ + "Export results to a CSV file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d4c8727", + "metadata": {}, + "outputs": [], + "source": [ + "data.export_data_to_csv(os.path.join(hfss.toolkit_directory, \"output.csv\"))" + ] + }, + { + "cell_type": "markdown", + "id": "4d4be926", + "metadata": {}, + "source": [ + "## Save project and close AEDT\n", + "\n", + "Save the project and close AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afbeba9d", + "metadata": {}, + "outputs": [], + "source": [ + "hfss.save_project()\n", + "hfss.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c88ae368", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49b08f52", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/stripline.ipynb.txt b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/stripline.ipynb.txt new file mode 100644 index 00000000..00d6d763 --- /dev/null +++ b/version/dev/_sources/examples/high_frequency/radiofrequency_mmwave/stripline.ipynb.txt @@ -0,0 +1,600 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "192bdb2c", + "metadata": {}, + "source": [ + "# Stripline analysis" + ] + }, + { + "cell_type": "markdown", + "id": "797fb4bf", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a differential stripline design in\n", + "2D Extractor and run a simulation.\n", + "\n", + "Keywords: **Q2D**, **Stripline**." + ] + }, + { + "cell_type": "markdown", + "id": "e068a066", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d9dbcef", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time\n", + "\n", + "import ansys.aedt.core\n" + ] + }, + { + "cell_type": "markdown", + "id": "cf71d940", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f84e44f", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4" + ] + }, + { + "cell_type": "markdown", + "id": "ab7e0b9f", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ae32d8c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "27ff22c8", + "metadata": {}, + "source": [ + "## Launch AEDT and 2D Extractor\n", + "\n", + "Launch AEDT 2024.2 in graphical mode and launch 2D Extractor. This example\n", + "uses SI units." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5867c5a", + "metadata": {}, + "outputs": [], + "source": [ + "q2d = ansys.aedt.core.Q2d(\n", + " project=os.path.join(temp_folder.name, \"stripline\"),\n", + " design=\"differential_stripline\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=False,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c082fcd0", + "metadata": {}, + "source": [ + "## Define variables\n", + "\n", + "Define variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "996a3c17", + "metadata": {}, + "outputs": [], + "source": [ + "e_factor = \"e_factor\"\n", + "sig_w = \"sig_bot_w\"\n", + "sig_gap = \"sig_gap\"\n", + "co_gnd_w = \"gnd_w\"\n", + "clearance = \"clearance\"\n", + "cond_h = \"cond_h\"\n", + "core_h = \"core_h\"\n", + "pp_h = \"pp_h\"\n", + "\n", + "for var_name, var_value in {\n", + " \"e_factor\": \"2\",\n", + " \"sig_bot_w\": \"150um\",\n", + " \"sig_gap\": \"150um\",\n", + " \"gnd_w\": \"500um\",\n", + " \"clearance\": \"150um\",\n", + " \"cond_h\": \"17um\",\n", + " \"core_h\": \"150um\",\n", + " \"pp_h\": \"150um\",\n", + "}.items():\n", + " q2d[var_name] = var_value\n", + "\n", + "delta_w_half = \"({0}/{1})\".format(cond_h, e_factor)\n", + "sig_top_w = \"({1}-{0}*2)\".format(delta_w_half, sig_w)\n", + "co_gnd_top_w = \"({1}-{0}*2)\".format(delta_w_half, co_gnd_w)\n", + "model_w = \"{}*2+{}*2+{}*2+{}\".format(co_gnd_w, clearance, sig_w, sig_gap)" + ] + }, + { + "cell_type": "markdown", + "id": "e78ca3f5", + "metadata": {}, + "source": [ + "## Create primitives\n", + "\n", + "Create primitives and define the layer heights." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92b762ba", + "metadata": {}, + "outputs": [], + "source": [ + "layer_1_lh = 0\n", + "layer_1_uh = cond_h\n", + "layer_2_lh = layer_1_uh + \"+\" + core_h\n", + "layer_2_uh = layer_2_lh + \"+\" + cond_h\n", + "layer_3_lh = layer_2_uh + \"+\" + pp_h\n", + "layer_3_uh = layer_3_lh + \"+\" + cond_h" + ] + }, + { + "cell_type": "markdown", + "id": "b13809cd", + "metadata": {}, + "source": [ + "## Create positive signal\n", + "\n", + "Create a positive signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd34fafb", + "metadata": {}, + "outputs": [], + "source": [ + "signal_p_1 = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_lh, 0], [sig_w, layer_2_lh, 0]], name=\"signal_p_1\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d918569a", + "metadata": {}, + "outputs": [], + "source": [ + "signal_p_2 = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_uh, 0], [sig_top_w, layer_2_uh, 0]], name=\"signal_p_2\"\n", + ")\n", + "q2d.modeler.move([signal_p_2], [delta_w_half, 0, 0])\n", + "q2d.modeler.connect([signal_p_1, signal_p_2])\n", + "q2d.modeler.move(\n", + " assignment=[signal_p_1], vector=[\"{}+{}\".format(co_gnd_w, clearance), 0, 0]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f6f21541", + "metadata": {}, + "source": [ + "## Create negative signal\n", + "\n", + "Create a negative signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6823ea5", + "metadata": {}, + "outputs": [], + "source": [ + "signal_n_1 = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_lh, 0], [sig_w, layer_2_lh, 0]], name=\"signal_n_1\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "397c3163", + "metadata": {}, + "outputs": [], + "source": [ + "signal_n_2 = q2d.modeler.create_polyline(\n", + " points=[[0, layer_2_uh, 0], [sig_top_w, layer_2_uh, 0]], name=\"signal_n_2\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ae0e80e", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.move(assignment=[signal_n_2], vector=[delta_w_half, 0, 0])\n", + "q2d.modeler.connect([signal_n_1, signal_n_2])\n", + "q2d.modeler.move(\n", + " assignment=[signal_n_1],\n", + " vector=[\"{}+{}+{}+{}\".format(co_gnd_w, clearance, sig_w, sig_gap), 0, 0],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "23d452e7", + "metadata": {}, + "source": [ + "## Create reference ground plane\n", + "\n", + "Create a reference ground plane." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22f4df71", + "metadata": {}, + "outputs": [], + "source": [ + "ref_gnd_u = q2d.modeler.create_rectangle(\n", + " origin=[0, layer_1_lh, 0], sizes=[model_w, cond_h], name=\"ref_gnd_u\"\n", + ")\n", + "ref_gnd_l = q2d.modeler.create_rectangle(\n", + " origin=[0, layer_3_lh, 0], sizes=[model_w, cond_h], name=\"ref_gnd_l\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bdb3ae7d", + "metadata": {}, + "source": [ + "## Create dielectric\n", + "\n", + "Create a dielectric." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64ddbb68", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.modeler.create_rectangle(\n", + " origin=[0, layer_1_uh, 0],\n", + " sizes=[model_w, core_h],\n", + " name=\"Core\",\n", + " material=\"FR4_epoxy\",\n", + ")\n", + "q2d.modeler.create_rectangle(\n", + " origin=[0, layer_2_uh, 0],\n", + " sizes=[model_w, pp_h],\n", + " name=\"Prepreg\",\n", + " material=\"FR4_epoxy\",\n", + ")\n", + "q2d.modeler.create_rectangle(\n", + " origin=[0, layer_2_lh, 0],\n", + " sizes=[model_w, cond_h],\n", + " name=\"Filling\",\n", + " material=\"FR4_epoxy\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6e669410", + "metadata": {}, + "source": [ + "## Assign conductors\n", + "\n", + "Assign conductors to the signal." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66bdc44e", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.assign_single_conductor(\n", + " name=signal_p_1.name,\n", + " assignment=[signal_p_1],\n", + " conductor_type=\"SignalLine\",\n", + " solve_option=\"SolveOnBoundary\",\n", + " units=\"mm\",\n", + ")\n", + "\n", + "q2d.assign_single_conductor(\n", + " name=signal_n_1.name,\n", + " assignment=[signal_n_1],\n", + " conductor_type=\"SignalLine\",\n", + " solve_option=\"SolveOnBoundary\",\n", + " units=\"mm\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8a786cc1", + "metadata": {}, + "source": [ + "## Create reference ground\n", + "\n", + "Create a reference ground." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a60dbc2", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.assign_single_conductor(\n", + " name=\"gnd\",\n", + " assignment=[ref_gnd_u, ref_gnd_l],\n", + " conductor_type=\"ReferenceGround\",\n", + " solve_option=\"SolveOnBoundary\",\n", + " units=\"mm\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cbe35d67", + "metadata": {}, + "source": [ + "## Assign Huray model on signals\n", + "\n", + "Assign the Huray model on the signals." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c11820d", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.assign_huray_finitecond_to_edges(\n", + " signal_p_1.edges, radius=\"0.5um\", ratio=3, name=\"b_\" + signal_p_1.name\n", + ")\n", + "\n", + "q2d.assign_huray_finitecond_to_edges(\n", + " signal_n_1.edges, radius=\"0.5um\", ratio=3, name=\"b_\" + signal_n_1.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "34e6fd04", + "metadata": {}, + "source": [ + "## Define differential pair\n", + "\n", + "Define the differential pair." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "444502c4", + "metadata": {}, + "outputs": [], + "source": [ + "matrix = q2d.insert_reduced_matrix(\n", + " operation_name=q2d.MATRIXOPERATIONS.DiffPair,\n", + " assignment=[\"signal_p_1\", \"signal_n_1\"],\n", + " reduced_matrix=\"diff_pair\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "574f022b", + "metadata": {}, + "source": [ + "## Create setup, analyze, and plot\n", + "\n", + "Create a setup, analyze, and plot solution data." + ] + }, + { + "cell_type": "markdown", + "id": "7355975b", + "metadata": {}, + "source": [ + "Create a setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b141c7e", + "metadata": {}, + "outputs": [], + "source": [ + "setup = q2d.create_setup(name=\"new_setup\")" + ] + }, + { + "cell_type": "markdown", + "id": "4ed88c19", + "metadata": {}, + "source": [ + "Add a sweep." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "822a229d", + "metadata": {}, + "outputs": [], + "source": [ + "sweep = setup.add_sweep(name=\"sweep1\", sweep_type=\"Discrete\")\n", + "sweep.props[\"RangeType\"] = \"LinearStep\"\n", + "sweep.props[\"RangeStart\"] = \"1GHz\"\n", + "sweep.props[\"RangeStep\"] = \"100MHz\"\n", + "sweep.props[\"RangeEnd\"] = \"5GHz\"\n", + "sweep.props[\"SaveFields\"] = False\n", + "sweep.props[\"SaveRadFields\"] = False\n", + "sweep.props[\"Type\"] = \"Interpolating\"\n", + "sweep.update()" + ] + }, + { + "cell_type": "markdown", + "id": "0ea18361", + "metadata": {}, + "source": [ + "Analyze the nominal design and plot characteristic impedance." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fb203e1", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.analyze(cores=NUM_CORES)\n", + "plot_sources = matrix.get_sources_for_plot(category=\"Z0\")" + ] + }, + { + "cell_type": "markdown", + "id": "6d5f15cf", + "metadata": {}, + "source": [ + "Get simulation results as a ``SolutionData`` object and plot to a JPG file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3eea93db", + "metadata": {}, + "outputs": [], + "source": [ + "data = q2d.post.get_solution_data(expressions=plot_sources, context=matrix.name)\n", + "data.plot(snapshot_path=os.path.join(temp_folder.name, \"plot.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "4cf1d5c2", + "metadata": {}, + "source": [ + "-" + ] + }, + { + "cell_type": "markdown", + "id": "15fb5ec7", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da275a3f", + "metadata": {}, + "outputs": [], + "source": [ + "q2d.save_project()\n", + "q2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "aef4a95c", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30d22a00", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/index.rst.txt b/version/dev/_sources/examples/index.rst.txt new file mode 100644 index 00000000..c0150441 --- /dev/null +++ b/version/dev/_sources/examples/index.rst.txt @@ -0,0 +1,97 @@ +.. _ref_examples: + +Examples +======== +This repository contains end-to-end embedding examples that demonstrate how to use +`PyAEDT `_. + +.. grid:: 2 + + .. grid-item-card:: PyAEDT basics + :padding: 2 2 2 2 + :link: https://aedt.docs.pyansys.com/version/stable/User_guide/index.html + :link-type: url + + .. image:: basic/_static/logo.png + :alt: PyAEDT logo + :width: 250px + :height: 200px + :align: center + + Links to brief tutorials provided in the PyAEDT documentation. + + .. grid-item-card:: Examples by AEDT application + :padding: 2 2 2 2 + :link: aedt/index + :link-type: doc + + .. image:: aedt/_static/aedt.png + :alt: AEDT + :width: 250px + :height: 200px + :align: center + + Provides examples organized by AEDT applications. + + .. grid-item-card:: High Frequency + :padding: 2 2 2 2 + :link: high_frequency/index + :link-type: doc + + .. image:: high_frequency/_static/hf.png + :alt: High frequency IC + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for high-frequency applications. + + .. grid-item-card:: Low Frequency + :padding: 2 2 2 2 + :link: low_frequency/index + :link-type: doc + + .. image:: low_frequency/_static/motor_maxwell.png + :alt: Low frequency motor + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for low-frequency applications. + + .. grid-item-card:: Electrothermal + :padding: 2 2 2 2 + :link: electrothermal/index + :link-type: doc + + .. image:: electrothermal/_static/icepak_logo.png + :alt: Icepak + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for electrothermal applications. + + .. grid-item-card:: Pre-processing and post-processing + :padding: 2 2 2 2 + :link: aedt_general/index + :link-type: doc + + .. image:: aedt_general/_static/aedt_electronics.png + :alt: AEDT electronics + :width: 250px + :height: 200px + :align: center + + Provides examples of some general PyAEDT pre-processing and post-processing capabilities. + + +.. toctree:: + :hidden: + :maxdepth: 2 + + aedt/index + high_frequency/index + low_frequency/index + electrothermal/index + aedt_general/index \ No newline at end of file diff --git a/version/dev/_sources/examples/low_frequency/general/control_program.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/control_program.ipynb.txt new file mode 100644 index 00000000..8d85b865 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/control_program.ipynb.txt @@ -0,0 +1,308 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "073f4262", + "metadata": {}, + "source": [ + "# Control program enablement" + ] + }, + { + "cell_type": "markdown", + "id": "d898691a", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to enable a control program in a Maxwell 2D project.\n", + "It shows how to create the geometry, load material properties from an Excel file, and\n", + "set up the mesh settings. Moreover, it focuses on postprocessing operations, in particular how to\n", + "plot field line traces, which are relevant for an electrostatic analysis.\n", + "\n", + "Keywords: **Maxwell 2D**, **control program**." + ] + }, + { + "cell_type": "markdown", + "id": "8d745d23", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a4c6fbd", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eac14dfc", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Maxwell2d, downloads" + ] + }, + { + "cell_type": "markdown", + "id": "22ad1a77", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fef59f02", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "84bb1ec0", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9a6cf4a", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "4f016387", + "metadata": {}, + "source": [ + "## Download project file\n", + "\n", + "Download the files required to run this example to the temporary working folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fdd6f581", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_file = downloads.download_file(\n", + " source=\"maxwell_ctrl_prg\",\n", + " name=\"ControlProgramDemo.aedt\",\n", + " destination=temp_folder.name,\n", + ")\n", + "ctrl_prg_file = downloads.download_file(\n", + " source=\"maxwell_ctrl_prg\", name=\"timestep_only.py\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b7ba7ff4", + "metadata": {}, + "source": [ + "## Launch Maxwell 2D\n", + "\n", + "Create an instance of the ``Maxwell2d`` class named ``m2d``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "457542f3", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = Maxwell2d(\n", + " project=aedt_file,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0fb1cfbf", + "metadata": {}, + "source": [ + "## Set active design" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea873e59", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.set_active_design(\"1 time step control\")" + ] + }, + { + "cell_type": "markdown", + "id": "9f23cc2f", + "metadata": {}, + "source": [ + "## Get setup\n", + "\n", + "Get the simulation setup for this design so that the control program can be enabled." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd79b25c", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m2d.setups[0]" + ] + }, + { + "cell_type": "markdown", + "id": "cd270153", + "metadata": {}, + "source": [ + "## Enable control program\n", + "\n", + "Enable the control program by giving the path to the file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b1636ef", + "metadata": {}, + "outputs": [], + "source": [ + "setup.enable_control_program(control_program_path=ctrl_prg_file)" + ] + }, + { + "cell_type": "markdown", + "id": "6aef7734", + "metadata": {}, + "source": [ + "## Analyze setup\n", + "\n", + "Run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e45d0a3", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.analyze(setup=setup.name, cores=NUM_CORES, use_auto_settings=False)" + ] + }, + { + "cell_type": "markdown", + "id": "973a4f63", + "metadata": {}, + "source": [ + "## Plot results\n", + "\n", + "Display the simulation results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30744fee", + "metadata": {}, + "outputs": [], + "source": [ + "sols = m2d.post.get_solution_data(\n", + " expressions=\"FluxLinkage(Winding1)\",\n", + " variations={\"Time\": [\"All\"]},\n", + " primary_sweep_variable=\"Time\",\n", + ")\n", + "sols.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "028efae5", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2ec51eb", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1e6ac14b", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7432e59", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/dc_analysis.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/dc_analysis.ipynb.txt new file mode 100644 index 00000000..390d0431 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/dc_analysis.ipynb.txt @@ -0,0 +1,373 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6720e09a", + "metadata": {}, + "source": [ + "# Electro DC analysis" + ] + }, + { + "cell_type": "markdown", + "id": "6bdaca87", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a Maxwell DC analysis,\n", + "compute mass center, and move coordinate systems.\n", + "\n", + "Keywords: **Maxwell 3D**, **DC**." + ] + }, + { + "cell_type": "markdown", + "id": "cb5406cd", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8291217e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b816e599", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Maxwell3d" + ] + }, + { + "cell_type": "markdown", + "id": "be592d99", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d839845", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "265ef40d", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe4df111", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "fea6235a", + "metadata": {}, + "source": [ + "## Launch AEDT\n", + "\n", + "Create an instance of the ``Maxwell3d`` class named ``m3d`` by providing\n", + "the project name, the version, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f23ab2d0", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"conductor_example.aedt\")\n", + "m3d = Maxwell3d(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d051e987", + "metadata": {}, + "source": [ + "## Set up Maxwell solution\n", + "\n", + "Set up the Maxwell solution to DC." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a56da3f4", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.solution_type = m3d.SOLUTIONS.Maxwell3d.ElectroDCConduction" + ] + }, + { + "cell_type": "markdown", + "id": "03890332", + "metadata": {}, + "source": [ + "## Create conductor\n", + "\n", + "Create a conductor using copper, a predefined material in the Maxwell material library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b8be7c5", + "metadata": {}, + "outputs": [], + "source": [ + "conductor = m3d.modeler.create_box(\n", + " origin=[7, 4, 22], sizes=[10, 5, 30], name=\"Conductor\", material=\"copper\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "be37ef84", + "metadata": {}, + "source": [ + "## Create setup and assign voltage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0081e1b5", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.assign_voltage(assignment=conductor.faces, amplitude=0)\n", + "m3d.create_setup()" + ] + }, + { + "cell_type": "markdown", + "id": "b15cd2bf", + "metadata": {}, + "source": [ + "## Solve setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69bf3e10", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "a372fd3e", + "metadata": {}, + "source": [ + "## Compute mass center\n", + "\n", + "Compute mass center using PyAEDT advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b62c5a2", + "metadata": {}, + "outputs": [], + "source": [ + "scalar_function = \"\"\n", + "mass_center = {\n", + " \"name\": \"\",\n", + " \"description\": \"Mass center computation\",\n", + " \"design_type\": [\"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"distance\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Solid\"],\n", + " \"operations\": [\n", + " scalar_function,\n", + " \"EnterVolume('assignment')\",\n", + " \"Operation('VolumeValue')\",\n", + " \"Operation('Mean')\",\n", + " ],\n", + " \"report\": [\"Data Table\"],\n", + "}\n", + "mass_center[\"name\"] = \"CM_X\"\n", + "scalar_function = \"Scalar_Function(FuncValue='X')\"\n", + "mass_center[\"operations\"][0] = scalar_function\n", + "m3d.post.fields_calculator.add_expression(mass_center, conductor.name)\n", + "mass_center[\"name\"] = \"CM_Y\"\n", + "scalar_function = \"Scalar_Function(FuncValue='Y')\"\n", + "mass_center[\"operations\"][0] = scalar_function\n", + "m3d.post.fields_calculator.add_expression(mass_center, conductor.name)\n", + "mass_center[\"name\"] = \"CM_Z\"\n", + "scalar_function = \"Scalar_Function(FuncValue='Z')\"\n", + "mass_center[\"operations\"][0] = scalar_function\n", + "m3d.post.fields_calculator.add_expression(mass_center, conductor.name)" + ] + }, + { + "cell_type": "markdown", + "id": "f049b079", + "metadata": {}, + "source": [ + "## Get mass center\n", + "\n", + "Get mass center using the fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c282e3a", + "metadata": {}, + "outputs": [], + "source": [ + "xval = m3d.post.get_scalar_field_value(quantity=\"CM_X\")\n", + "yval = m3d.post.get_scalar_field_value(quantity=\"CM_Y\")\n", + "zval = m3d.post.get_scalar_field_value(quantity=\"CM_Z\")" + ] + }, + { + "cell_type": "markdown", + "id": "eba2a752", + "metadata": {}, + "source": [ + "## Create variables\n", + "\n", + "Create variables with mass center values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1aac6a08", + "metadata": {}, + "outputs": [], + "source": [ + "m3d[conductor.name + \"x\"] = str(xval * 1e3) + \"mm\"\n", + "m3d[conductor.name + \"y\"] = str(yval * 1e3) + \"mm\"\n", + "m3d[conductor.name + \"z\"] = str(zval * 1e3) + \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "b0e19888", + "metadata": {}, + "source": [ + "## Create coordinate system\n", + "\n", + "Create a parametric coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c17ba41", + "metadata": {}, + "outputs": [], + "source": [ + "cs1 = m3d.modeler.create_coordinate_system(\n", + " origin=[conductor.name + \"x\", conductor.name + \"y\", conductor.name + \"z\"],\n", + " reference_cs=\"Global\",\n", + " name=conductor.name + \"CS\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0a8e6a44", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d96902a3", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "1621d420", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "651bf3a4", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/eddy_current.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/eddy_current.ipynb.txt new file mode 100644 index 00000000..18f0c282 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/eddy_current.ipynb.txt @@ -0,0 +1,348 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d50b3463", + "metadata": {}, + "source": [ + "# Eddy current analysis and reduced matrix" + ] + }, + { + "cell_type": "markdown", + "id": "28f4f311", + "metadata": {}, + "source": [ + "This example shows how to leverage PyAEDT to assign a matrix\n", + "and perform series or parallel connections in a Maxwell 2D design.\n", + "\n", + "Keywords: **Maxwell 2D**, **eddy current**, *matrix**." + ] + }, + { + "cell_type": "markdown", + "id": "4aba15de", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a602012a", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "97c03c10", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "28a7949b", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5480157", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "96c2eb9a", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b948fedd", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "cbe028a9", + "metadata": {}, + "source": [ + "## Download AEDT file\n", + "\n", + "Set the local temporary folder to export the AEDT file to." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9061a198", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"maxwell_ec_reduced_matrix\",\n", + " name=\"m2d_eddy_current.aedt\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bc65a128", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D, providing the version, path to the project, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "144d5588", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = ansys.aedt.core.Maxwell2d(\n", + " project=project_path,\n", + " version=AEDT_VERSION,\n", + " design=\"EC_Planar\",\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b67c49e1", + "metadata": {}, + "source": [ + "## Assign a matrix\n", + "\n", + "Assign a matrix given the list of sources to assign the matrix to and the return path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79894bc9", + "metadata": {}, + "outputs": [], + "source": [ + "matrix = m2d.assign_matrix(\n", + " assignment=[\"pri\", \"sec\", \"terz\"], matrix_name=\"Matrix1\", return_path=\"infinite\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "daad6c22", + "metadata": {}, + "source": [ + "## Assign reduced matrices\n", + "\n", + "Assign reduced matrices to the parent matrix previously created.\n", + "For 2D/3D Eddy current solvers, two or more excitations can be joined\n", + "either in series or parallel connection. The result is known as a reduced matrix." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3724f3f6", + "metadata": {}, + "outputs": [], + "source": [ + "series = matrix.join_series(sources=[\"pri\", \"sec\"], matrix_name=\"ReducedMatrix1\")\n", + "parallel = matrix.join_parallel(sources=[\"sec\", \"terz\"], matrix_name=\"ReducedMatrix2\")" + ] + }, + { + "cell_type": "markdown", + "id": "199679c2", + "metadata": {}, + "source": [ + "## Analyze setup\n", + "\n", + "Run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1d8c1e02", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.analyze(setup=m2d.setup_names[0], cores=NUM_CORES, use_auto_settings=False)" + ] + }, + { + "cell_type": "markdown", + "id": "2b13cdae", + "metadata": {}, + "source": [ + "## Get expressions\n", + "\n", + "Get the available report quantities given the context\n", + "and the quantities category ``L``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22f3ef53", + "metadata": {}, + "outputs": [], + "source": [ + "expressions = m2d.post.available_report_quantities(\n", + " report_category=\"EddyCurrent\",\n", + " display_type=\"Data Table\",\n", + " context={\"Matrix1\": \"ReducedMatrix1\"},\n", + " quantities_category=\"L\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "976e6047", + "metadata": {}, + "source": [ + "## Create report and get solution data\n", + "\n", + "Create a data table report and get report data given the matrix context." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b99f5c0", + "metadata": {}, + "outputs": [], + "source": [ + "report = m2d.post.create_report(\n", + " expressions=expressions,\n", + " context={\"Matrix1\": \"ReducedMatrix1\"},\n", + " plot_type=\"Data Table\",\n", + " setup_sweep_name=\"Setup1 : LastAdaptive\",\n", + " plot_name=\"reduced_matrix\",\n", + ")\n", + "data = m2d.post.get_solution_data(\n", + " expressions=expressions,\n", + " context={\"Matrix1\": \"ReducedMatrix1\"},\n", + " report_category=\"EddyCurrent\",\n", + " setup_sweep_name=\"Setup1 : LastAdaptive\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "dbb7f1f4", + "metadata": {}, + "source": [ + "## Get matrix data\n", + "\n", + "Get inductance results for the join connections in ``nH``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfb0f6c5", + "metadata": {}, + "outputs": [], + "source": [ + "ind = ansys.aedt.core.generic.constants.unit_converter(\n", + " data.data_magnitude()[0],\n", + " unit_system=\"Inductance\",\n", + " input_units=data.units_data[expressions[0]],\n", + " output_units=\"uH\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "df874f5b", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd029a83", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "8c08d165", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6df669b", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/electrostatic.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/electrostatic.ipynb.txt new file mode 100644 index 00000000..28c53b6b --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/electrostatic.ipynb.txt @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8376d328", + "metadata": {}, + "source": [ + "# Electrostatic analysis" + ] + }, + { + "cell_type": "markdown", + "id": "55161dec", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to create a Maxwell 2D electrostatic analysis.\n", + "It shows how to create the geometry, load material properties from a Microsoft Excel file, and\n", + "set up the mesh settings. Moreover, it focuses on postprocessing operations, in particular how to\n", + "plot field line traces, which are relevant for an electrostatic analysis.\n", + "\n", + "Keywords: **Maxwell 2D**, **electrostatic**." + ] + }, + { + "cell_type": "markdown", + "id": "17d9bb8d", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "743aa44c", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc8a0269", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "2240345e", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42e349d3", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False" + ] + }, + { + "cell_type": "markdown", + "id": "79dc5e5a", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``.." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f28e7bae", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "1ed12dc7", + "metadata": {}, + "source": [ + "## Download Excel file\n", + "\n", + "Set the local temporary folder to export the Excel (XLSX) file to." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a384285", + "metadata": {}, + "outputs": [], + "source": [ + "file_name_xlsx = ansys.aedt.core.downloads.download_file(\n", + " source=\"field_line_traces\", name=\"my_copper.xlsx\", destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "307d8a14", + "metadata": {}, + "source": [ + "## Initialize dictionaries\n", + "\n", + "Initialize the dictionaries that contain all the definitions for the design variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "520cc2d3", + "metadata": {}, + "outputs": [], + "source": [ + "geom_params_circle = {\n", + " \"circle_x0\": \"-10mm\",\n", + " \"circle_y0\": \"0mm\",\n", + " \"circle_z0\": \"0mm\",\n", + " \"circle_axis\": \"Z\",\n", + " \"circle_radius\": \"1mm\",\n", + "}\n", + "\n", + "geom_params_rectangle = {\n", + " \"r_x0\": \"1mm\",\n", + " \"r_y0\": \"5mm\",\n", + " \"r_z0\": \"0mm\",\n", + " \"r_axis\": \"Z\",\n", + " \"r_dx\": \"-1mm\",\n", + " \"r_dy\": \"-10mm\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "391840f4", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D after first setting up the project and design names,\n", + "the solver, and the version. The following code also creates an instance of the\n", + "``Maxwell2d`` class named ``m2d``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8a70e00", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"M2D_Electrostatic.aedt\")\n", + "m2d = ansys.aedt.core.Maxwell2d(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " design=\"Design1\",\n", + " solution_type=\"Electrostatic\",\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c250feec", + "metadata": {}, + "source": [ + "## Set modeler units\n", + "\n", + "Set modeler units to ``mm``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bedb4fab", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "76c5ca4d", + "metadata": {}, + "source": [ + "## Define variables from dictionaries\n", + "\n", + "Define design variables from the created dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2929300b", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in geom_params_circle.items():\n", + " m2d[k] = v\n", + "for k, v in geom_params_rectangle.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "4f295028", + "metadata": {}, + "source": [ + "## Read materials from Excel file\n", + "\n", + "Read materials from the Excel file into the design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e3b1db6", + "metadata": {}, + "outputs": [], + "source": [ + "mats = m2d.materials.import_materials_from_excel(file_name_xlsx)" + ] + }, + { + "cell_type": "markdown", + "id": "178ac0f2", + "metadata": {}, + "source": [ + "## Create design geometries\n", + "\n", + "Create a rectangle and a circle. Assign the material read from the Excel file.\n", + "Create two new polylines and a region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3cbcee24", + "metadata": {}, + "outputs": [], + "source": [ + "rect = m2d.modeler.create_rectangle(\n", + " origin=[\"r_x0\", \"r_y0\", \"r_z0\"],\n", + " sizes=[\"r_dx\", \"r_dy\", 0],\n", + " name=\"Ground\",\n", + " material=mats[0],\n", + ")\n", + "rect.color = (0, 0, 255) # rgb\n", + "rect.solve_inside = False\n", + "\n", + "circle = m2d.modeler.create_circle(\n", + " origin=[\"circle_x0\", \"circle_y0\", \"circle_z0\"],\n", + " radius=\"circle_radius\",\n", + " num_sides=\"0\",\n", + " is_covered=True,\n", + " name=\"Electrode\",\n", + " material=mats[0],\n", + ")\n", + "circle.color = (0, 0, 255) # rgb\n", + "circle.solve_inside = False\n", + "\n", + "poly1_points = [[-9, 2, 0], [-4, 2, 0], [2, -2, 0], [8, 2, 0]]\n", + "poly2_points = [[-9, 0, 0], [9, 0, 0]]\n", + "poly1_id = m2d.modeler.create_polyline(\n", + " points=poly1_points, segment_type=\"Spline\", name=\"Poly1\"\n", + ")\n", + "poly2_id = m2d.modeler.create_polyline(points=poly2_points, name=\"Poly2\")\n", + "m2d.modeler.split(assignment=[poly1_id, poly2_id], plane=\"YZ\", sides=\"NegativeOnly\")\n", + "m2d.modeler.create_region(pad_value=[20, 100, 20, 100])" + ] + }, + { + "cell_type": "markdown", + "id": "3bab8e67", + "metadata": {}, + "source": [ + "## Define excitations\n", + "\n", + "Assign voltage excitations to the rectangle and circle." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a30bad40", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_voltage(assignment=rect.id, amplitude=0, name=\"Ground\")\n", + "m2d.assign_voltage(assignment=circle.id, amplitude=50e6, name=\"50kV\")" + ] + }, + { + "cell_type": "markdown", + "id": "43dff15e", + "metadata": {}, + "source": [ + "## Create initial mesh settings\n", + "\n", + "Assign a surface mesh to the rectangle." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7262de1", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_surface_mesh_manual(assignment=[\"Ground\"], surface_deviation=0.001)" + ] + }, + { + "cell_type": "markdown", + "id": "43a4d583", + "metadata": {}, + "source": [ + "## Create, validate, and analyze setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5526d1f6", + "metadata": {}, + "outputs": [], + "source": [ + "setup_name = \"MySetupAuto\"\n", + "setup = m2d.create_setup(name=setup_name)\n", + "setup.props[\"PercentError\"] = 0.5\n", + "setup.update()\n", + "m2d.validate_simple()\n", + "m2d.analyze_setup(name=setup_name, use_auto_settings=False, cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "bf642f4b", + "metadata": {}, + "source": [ + "## Evaluate the E Field tangential component\n", + "\n", + "Evaluate the E Field tangential component along the given polylines.\n", + "Add these operations to the **Named Expression** list in the field calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7219d40d", + "metadata": {}, + "outputs": [], + "source": [ + "e_line = m2d.post.fields_calculator.add_expression(\n", + " calculation=\"e_line\", assignment=None\n", + ")\n", + "m2d.post.fields_calculator.expression_plot(\n", + " calculation=\"e_line\", assignment=\"Poly1\", names=[e_line]\n", + ")\n", + "m2d.post.fields_calculator.expression_plot(\n", + " calculation=\"e_line\", assignment=\"Poly12\", names=[e_line]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bb2abddc", + "metadata": {}, + "source": [ + "## Create field line traces plot\n", + "\n", + "Create a field line traces plot specifying as seeding faces\n", + "the ground, the electrode, and the region\n", + "and as ``In surface objects`` only the region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f54872c", + "metadata": {}, + "outputs": [], + "source": [ + "plot = m2d.post.create_fieldplot_line_traces(\n", + " seeding_faces=[\"Ground\", \"Electrode\", \"Region\"],\n", + " in_volume_tracing_objs=[\"Region\"],\n", + " plot_name=\"LineTracesTest\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "51455380", + "metadata": {}, + "source": [ + "## Update field line traces plot\n", + "\n", + "Update the field line traces plot.\n", + "Update the seeding points number, line style, and line width." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18f7816f", + "metadata": {}, + "outputs": [], + "source": [ + "plot.SeedingPointsNumber = 20\n", + "plot.LineStyle = \"Cylinder\"\n", + "plot.LineWidth = 3\n", + "plot.update()" + ] + }, + { + "cell_type": "markdown", + "id": "a76cff45", + "metadata": {}, + "source": [ + "## Export field line traces plot\n", + "\n", + "Export the field line traces plot.\n", + "For the field lint traces plot, the export file format is ``.fldplt``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5128476", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.export_field_plot(\n", + " plot_name=\"LineTracesTest\", output_dir=temp_folder.name, file_format=\"fldplt\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a5197952", + "metadata": {}, + "source": [ + "## Export mesh field plot\n", + "\n", + "Export the mesh to an AEDTPLT file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7103af36", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.export_mesh_obj(setup=m2d.nominal_adaptive)" + ] + }, + { + "cell_type": "markdown", + "id": "15a344b1", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc4f5960", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "c6aa2183", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c603722", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/external_circuit.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/external_circuit.ipynb.txt new file mode 100644 index 00000000..14cf9406 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/external_circuit.ipynb.txt @@ -0,0 +1,627 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ecd03280", + "metadata": {}, + "source": [ + "# External delta circuit\n", + "\n", + "This example shows how to create an external delta circuit and connect it with a Maxwell 2D design.\n", + "\n", + "Keywords: **Maxwell 2D**, **Circuit**, **netlist**" + ] + }, + { + "cell_type": "markdown", + "id": "44c88a9c", + "metadata": {}, + "source": [ + "## Perform imports and define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18b9f757", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f68139df", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "2f1323d4", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa4e8cd2", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "97d8a24d", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "864bdc16", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "2c0d9950", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D providing the version, path to the project, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af47ad0c", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"Maxwell_circuit_example.aedt\")\n", + "design_name = \"1 Maxwell\"\n", + "circuit_name = \"2 Delta circuit\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f9b7c89", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = ansys.aedt.core.Maxwell2d(\n", + " version=AEDT_VERSION,\n", + " new_desktop=False,\n", + " design=design_name,\n", + " project=project_name,\n", + " solution_type=\"TransientXY\",\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0d78d323", + "metadata": {}, + "source": [ + "## Initialize dictionaries and define variables\n", + "\n", + "Initialize dictionaries that contain all design variable definitions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9c10c62", + "metadata": {}, + "outputs": [], + "source": [ + "voltage = \"230V\"\n", + "frequency = \"50Hz\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "547abeb0", + "metadata": {}, + "outputs": [], + "source": [ + "transient_parameters = {\n", + " \"voltage\": voltage,\n", + " \"frequency\": frequency,\n", + " \"electric_period\": \"1 / frequency s\",\n", + " \"stop_time\": \"2 * electric_period s\",\n", + " \"time_step\": \"electric_period / 20 s\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51782b4a", + "metadata": {}, + "outputs": [], + "source": [ + "circuit_parameters = {\n", + " \"voltage\": voltage,\n", + " \"frequency\": frequency,\n", + " \"resistance_value\": \"1Ohm\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13de1bf5", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in transient_parameters.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "91031b75", + "metadata": {}, + "source": [ + "## Create geometry\n", + "\n", + "Create copper coils and a vacuum region. Assign mesh operations, and then assign a balloon boundary to the region edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25deffb4", + "metadata": {}, + "outputs": [], + "source": [ + "coil1_id = m2d.modeler.create_circle(\n", + " orientation=\"Z\", origin=[0, 0, 0], radius=10, name=\"coil1\", material=\"copper\"\n", + ")\n", + "coil2_id = m2d.modeler.create_circle(\n", + " orientation=\"Z\", origin=[25, 0, 0], radius=10, name=\"coil2\", material=\"copper\"\n", + ")\n", + "coil3_id = m2d.modeler.create_circle(\n", + " orientation=\"Z\", origin=[50, 0, 0], radius=10, name=\"coil3\", material=\"copper\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66926124", + "metadata": {}, + "outputs": [], + "source": [ + "region = m2d.modeler.create_region(pad_value=[200, 400, 200, 400])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e7c24dc", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_length_mesh(\n", + " assignment=[coil1_id, coil2_id, coil3_id, region], maximum_length=5\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f9e59ea", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_vector_potential(assignment=region.edges, vector_value=0)" + ] + }, + { + "cell_type": "markdown", + "id": "156cd26f", + "metadata": {}, + "source": [ + "## Assign excitations\n", + "\n", + "Assign external windings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cbee1a82", + "metadata": {}, + "outputs": [], + "source": [ + "wdg1 = m2d.assign_winding(\n", + " assignment=[\"coil1\"],\n", + " is_solid=False,\n", + " winding_type=\"External\",\n", + " name=\"winding1\",\n", + " current=0,\n", + ")\n", + "wdg2 = m2d.assign_winding(\n", + " assignment=[\"coil2\"],\n", + " is_solid=False,\n", + " winding_type=\"External\",\n", + " name=\"winding2\",\n", + " current=0,\n", + ")\n", + "wdg3 = m2d.assign_winding(\n", + " assignment=[\"coil3\"],\n", + " is_solid=False,\n", + " winding_type=\"External\",\n", + " name=\"winding3\",\n", + " current=0,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d0ce85fb", + "metadata": {}, + "source": [ + "## Create simulation setup\n", + "\n", + "Create the simulation setup, defining the stop time and time step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d56eb237", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m2d.create_setup()\n", + "setup[\"StopTime\"] = \"stop_time\"\n", + "setup[\"TimeStep\"] = \"time_step\"" + ] + }, + { + "cell_type": "markdown", + "id": "694e737e", + "metadata": {}, + "source": [ + "## Create external circuit\n", + "\n", + "Create the circuit design, including all windings of type ``External`` in the Maxwell design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3021b99", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = m2d.create_external_circuit(circuit_design=circuit_name)" + ] + }, + { + "cell_type": "markdown", + "id": "7ec06dfa", + "metadata": {}, + "source": [ + "## Define variables from dictionaries\n", + "\n", + "Define design variables from the created dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12dd532d", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in circuit_parameters.items():\n", + " circuit[k] = v" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b70553df", + "metadata": {}, + "outputs": [], + "source": [ + "windings = [\n", + " circuit.modeler.schematic.components[k]\n", + " for k in list(circuit.modeler.schematic.components.keys())\n", + " if circuit.modeler.schematic.components[k].parameters[\"Info\"] == \"Winding\"\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "899a7c8b", + "metadata": {}, + "source": [ + "## Finalize external circuit\n", + "\n", + "Draw these other components: resistors, voltage sources, and grounds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6aeb5554", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.modeler.schematic_units = \"mil\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42497c16", + "metadata": {}, + "outputs": [], + "source": [ + "resistors = []\n", + "v_sources = []\n", + "ground = []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09e053c7", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(len(windings)):\n", + " r = circuit.modeler.schematic.create_resistor(\n", + " name=\"R\" + str(i + 1), value=\"resistance_value\", location=[1000, i * 1000]\n", + " )\n", + " resistors.append(r)\n", + "\n", + " v = circuit.modeler.schematic.create_component(\n", + " component_library=\"Sources\",\n", + " component_name=\"VSin\",\n", + " location=[2000, i * 1000],\n", + " angle=90,\n", + " )\n", + " v_sources.append(v)\n", + "\n", + " v.parameters[\"Va\"] = \"voltage\"\n", + " v.parameters[\"VFreq\"] = \"frequency\"\n", + " v.parameters[\"Phase\"] = str(i * 120) + \"deg\"\n", + "\n", + " g = circuit.modeler.schematic.create_gnd([2300, i * 1000], angle=90)\n", + " ground.append(g)" + ] + }, + { + "cell_type": "markdown", + "id": "9222074a", + "metadata": {}, + "source": [ + "## Connect components\n", + "\n", + "Connect the components by drawing wires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2f50e01", + "metadata": {}, + "outputs": [], + "source": [ + "windings[2].pins[1].connect_to_component(resistors[2].pins[0], use_wire=True)\n", + "windings[1].pins[1].connect_to_component(resistors[1].pins[0], use_wire=True)\n", + "windings[0].pins[1].connect_to_component(resistors[0].pins[0], use_wire=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea9912d9", + "metadata": {}, + "outputs": [], + "source": [ + "resistors[2].pins[1].connect_to_component(v_sources[2].pins[1], use_wire=True)\n", + "resistors[1].pins[1].connect_to_component(v_sources[1].pins[1], use_wire=True)\n", + "resistors[0].pins[1].connect_to_component(v_sources[0].pins[1], use_wire=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f000eb1", + "metadata": {}, + "outputs": [], + "source": [ + "circuit.modeler.schematic.create_wire(\n", + " points=[\n", + " resistors[2].pins[1].location,\n", + " [1200, 2500],\n", + " [-600, 2500],\n", + " [-600, 0],\n", + " windings[0].pins[0].location,\n", + " ]\n", + ")\n", + "circuit.modeler.schematic.create_wire(\n", + " points=[\n", + " resistors[1].pins[1].location,\n", + " [1200, 1500],\n", + " [-300, 1500],\n", + " [-300, 2000],\n", + " windings[2].pins[0].location,\n", + " ]\n", + ")\n", + "circuit.modeler.schematic.create_wire(\n", + " points=[\n", + " resistors[0].pins[1].location,\n", + " [1200, 500],\n", + " [-300, 500],\n", + " [-300, 1000],\n", + " windings[1].pins[0].location,\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d4066fb2", + "metadata": {}, + "source": [ + "## Export and import netlist\n", + "\n", + "Export the netlist file and then import it to Maxwell 2D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1c4c515", + "metadata": {}, + "outputs": [], + "source": [ + "netlist_file = os.path.join(temp_folder.name, \"_netlist.sph\")\n", + "circuit.export_netlist_from_schematic(netlist_file)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5841dcff", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.edit_external_circuit(\n", + " netlist_file_path=netlist_file, schematic_design_name=circuit_name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ed1b2c5c", + "metadata": {}, + "source": [ + "## Analyze setup\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "994f1d0c", + "metadata": {}, + "outputs": [], + "source": [ + "setup.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "f9890ee3", + "metadata": {}, + "source": [ + "## Create rectangular plot\n", + "\n", + "Plot winding currents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c61ea4ab", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.create_report(\n", + " expressions=[\"Current(winding1)\", \"Current(winding2)\", \"Current(winding3)\"],\n", + " domain=\"Sweep\",\n", + " primary_sweep_variable=\"Time\",\n", + " plot_name=\"Winding Currents\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "51829198", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ef33daf", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "360f0686", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_dir.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a60c0fa4", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/field_export.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/field_export.ipynb.txt new file mode 100644 index 00000000..5f4463e5 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/field_export.ipynb.txt @@ -0,0 +1,413 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ae07785c", + "metadata": {}, + "source": [ + "# Fields export in transient analysis\n", + "\n", + "This example shows how to leverage PyAEDT to set up a Maxwell 3D transient analysis and then\n", + "compute the average value of the current density field over a specific coil surface\n", + "and the magnitude of the current density field over all coil surfaces at each time step\n", + "of the transient analysis.\n", + "\n", + "Keywords: **Maxwell 3D**, **transient**, **fields calculator**, **field export**." + ] + }, + { + "cell_type": "markdown", + "id": "0f1a0cc0", + "metadata": {}, + "source": [ + "## Perform imports and define constant\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29a98c1b", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e208462", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "666d96b0", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0222467", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "c3b53a54", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0c569c2", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "18af5102", + "metadata": {}, + "source": [ + "## Import project\n", + "\n", + "The files required to run this example are downloaded into the temporary working folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81e502d4", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"maxwell_transient_fields\",\n", + " name=\"M3D_Transient_StrandedWindings.aedt\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c86c1a7c", + "metadata": {}, + "source": [ + "## Initialize and launch Maxwell 3D\n", + "\n", + "Initialize and launch Maxwell 3D, providing the version and the path of the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5eb5f83e", + "metadata": {}, + "outputs": [], + "source": [ + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=project_path, version=AEDT_VERSION, non_graphical=NG_MODE\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d38400f6", + "metadata": {}, + "source": [ + "## Create setup and validate\n", + "\n", + "Create the setup specifying general settings such as ``StopTime``, ``TimeStep``,\n", + "and ``SaveFieldsType``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1379a16", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m3d.create_setup(name=\"Setup1\")\n", + "setup.props[\"StopTime\"] = \"0.02s\"\n", + "setup.props[\"TimeStep\"] = \"0.002s\"\n", + "setup.props[\"SaveFieldsType\"] = \"Every N Steps\"\n", + "setup.props[\"N Steps\"] = \"2\"\n", + "setup.props[\"Steps From\"] = \"0s\"\n", + "setup.props[\"Steps To\"] = \"0.02s\"\n", + "setup.update()" + ] + }, + { + "cell_type": "markdown", + "id": "97aa4e62", + "metadata": {}, + "source": [ + "## Create field expressions\n", + "\n", + "Create a field expression to evaluate the J field normal to a surface using the advanced fields calculator.\n", + "The expression is created as a dictionary and then provided as an argument to the ``add_expression()`` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "202fed99", + "metadata": {}, + "outputs": [], + "source": [ + "j_normal = {\n", + " \"name\": \"Jn\",\n", + " \"description\": \"J field normal to a surface\",\n", + " \"design_type\": [\"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Time\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"\"],\n", + " \"operations\": [\n", + " \"NameOfExpression('')\",\n", + " \"Operation('Normal')\",\n", + " \"Operation('Dot')\",\n", + " ],\n", + " \"report\": [\"Field_3D\"],\n", + "}\n", + "m3d.post.fields_calculator.add_expression(j_normal, None)" + ] + }, + { + "cell_type": "markdown", + "id": "99fa4946", + "metadata": {}, + "source": [ + "Calculate the average value of the J field normal using the advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd3a4f76", + "metadata": {}, + "outputs": [], + "source": [ + "j_avg = {\n", + " \"name\": \"Jn_avg\",\n", + " \"description\": \"Average J field normal to a surface\",\n", + " \"design_type\": [\"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Time\",\n", + " \"assignment\": \"Coil_A2_ObjectFromFace1\",\n", + " \"assignment_type\": [\"\"],\n", + " \"operations\": [\n", + " \"NameOfExpression('Jn')\",\n", + " \"EnterSurface('assignment')\",\n", + " \"Operation('SurfaceValue')\",\n", + " \"Operation('Mean')\",\n", + " ],\n", + " \"report\": [\"Field_3D\"],\n", + "}\n", + "m3d.post.fields_calculator.add_expression(j_avg, None)" + ] + }, + { + "cell_type": "markdown", + "id": "0d6c880b", + "metadata": {}, + "source": [ + "## Analyze setup specifying setup name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c773a33e", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.analyze_setup(name=setup.name, cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "e80f708d", + "metadata": {}, + "source": [ + "## Get available report quantities\n", + "\n", + "Get the available report quantities given a specific report category.\n", + "In this case, ``Calculator Expressions`` is the category." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fbc98be", + "metadata": {}, + "outputs": [], + "source": [ + "report_types = m3d.post.available_report_types\n", + "quantity = m3d.post.available_report_quantities(\n", + " report_category=\"Fields\", quantities_category=\"Calculator Expressions\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "749a47da", + "metadata": {}, + "source": [ + "## Compute time steps of the analysis\n", + "\n", + "Create a fields report object given the nominal sweep.\n", + "Get the report solution data to compute the time steps of the transient analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05ef0409", + "metadata": {}, + "outputs": [], + "source": [ + "sol = m3d.post.reports_by_category.fields(setup=m3d.nominal_sweep)\n", + "data = sol.get_solution_data()\n", + "time_steps = data.intrinsics[\"Time\"]" + ] + }, + { + "cell_type": "markdown", + "id": "1100cb31", + "metadata": {}, + "source": [ + "## Create field plots over the coil surfaces and export field data\n", + "\n", + "Convert each time step into millimeters.\n", + "Create field plots over the surface of each coil by specifying the coil object,\n", + "the quantity to plot, and the time step.\n", + "\n", + "The average value of the J field normal is plotted on the ``Coil_A2`` surface for every time step.\n", + "The J field is plotted on the surface of each coil for every time-step.\n", + "Fields data is exported to the temporary folder as an AEDTPLT file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc44d5e4", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "for time_step in time_steps:\n", + " t = ansys.aedt.core.generic.constants.unit_converter(\n", + " time_step,\n", + " unit_system=\"Time\",\n", + " input_units=data.units_sweeps[\"Time\"],\n", + " output_units=\"ms\",\n", + " )\n", + " m3d.post.create_fieldplot_surface(\n", + " assignment=m3d.modeler.objects_by_name[\"Coil_A2\"],\n", + " quantity=quantity[0],\n", + " plot_name=\"J_{}_ms\".format(t),\n", + " intrinsics={\"Time\": \"{}ms\".format(t)},\n", + " )\n", + " mean_j_field_export = m3d.post.export_field_plot(\n", + " plot_name=\"J_{}_ms\".format(t),\n", + " output_dir=temp_folder.name,\n", + " file_format=\"aedtplt\",\n", + " )\n", + " m3d.post.create_fieldplot_surface(\n", + " assignment=[\n", + " o for o in m3d.modeler.solid_objects if o.material_name == \"copper\"\n", + " ],\n", + " quantity=\"Mag_J\",\n", + " plot_name=\"Mag_J_Coils_{}_ms\".format(t),\n", + " intrinsics={\"Time\": \"{}ms\".format(t)},\n", + " )\n", + " mag_j_field_export = m3d.post.export_field_plot(\n", + " plot_name=\"Mag_J_Coils_{}_ms\".format(t),\n", + " output_dir=temp_folder.name,\n", + " file_format=\"aedtplt\",\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "280d0887", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f513213f", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b0036c14", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffc407bc", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/index.rst.txt b/version/dev/_sources/examples/low_frequency/general/index.rst.txt new file mode 100644 index 00000000..7c8bac3c --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/index.rst.txt @@ -0,0 +1,130 @@ +General +~~~~~~~ + +These examples use PyAEDT to show some general applications. + +.. grid:: 2 + + .. grid-item-card:: Control program enablement + :padding: 2 2 2 2 + :link: control_program + :link-type: doc + + .. image:: _static/control_program.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to enable a control program in a Maxwell 2D project. + + + .. grid-item-card:: Resistance calculation + :padding: 2 2 2 2 + :link: resistance + :link-type: doc + + .. image:: _static/resistance.png + :alt: Maxwell resistance + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a resistance calculation and solve it using the Maxwell 2D DCConduction solver. + + + .. grid-item-card:: Eddy current analysis and reduced matrix + :padding: 2 2 2 2 + :link: eddy_current + :link-type: doc + + .. image:: _static/eddy_current.png + :alt: Maxwell Eddy current + :width: 250px + :height: 200px + :align: center + + This example shows how to leverage PyAEDT to assign a matrix and perform series or parallel connections in a Maxwell 2D design. + + + .. grid-item-card:: Electrostatic analysis + :padding: 2 2 2 2 + :link: electrostatic + :link-type: doc + + .. image:: _static/electrostatic.png + :alt: Maxwell electrostatic + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D electrostatic analysis. + + + .. grid-item-card:: External delta circuit + :padding: 2 2 2 2 + :link: external_circuit + :link-type: doc + + .. image:: _static/external_circuit.png + :alt: External circuit + :width: 250px + :height: 200px + :align: center + + This example shows how to create an external delta circuit and connect it with a Maxwell 2D design. + + + .. grid-item-card:: Electro DC analysis + :padding: 2 2 2 2 + :link: dc_analysis + :link-type: doc + + .. image:: _static/dc.png + :alt: Maxwell DC + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell DC analysis, compute mass center, and move coordinate systems. + + + .. grid-item-card:: Fields export in transient analysis + :padding: 2 2 2 2 + :link: field_export + :link-type: doc + + .. image:: _static/field.png + :alt: Maxwell field + :width: 250px + :height: 200px + :align: center + + This example shows how to leverage PyAEDT to set up a Maxwell 3D transient analysis and then + compute the average value of the current density field over a specific coil surface and the magnitude + of the current density field over all coil surfaces at each time step of the transient analysis. + + .. grid-item-card:: Twin builder + :padding: 2 2 2 2 + :link: twin_builder/index + :link-type: doc + + .. image:: twin_builder/_static/rectifier.png + :alt: Rectifier + :width: 250px + :height: 200px + :align: center + + Twin builder examples. + + .. toctree:: + :hidden: + + control_program + resistance + eddy_current + electrostatic + external_circuit + dc_analysis + field_export + twin_builder/index diff --git a/version/dev/_sources/examples/low_frequency/general/resistance.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/resistance.ipynb.txt new file mode 100644 index 00000000..22a21be2 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/resistance.ipynb.txt @@ -0,0 +1,776 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ac713cb2", + "metadata": {}, + "source": [ + "# Resistance calculation" + ] + }, + { + "cell_type": "markdown", + "id": "0579aee6", + "metadata": {}, + "source": [ + "This example uses PyAEDT to set up a resistance calculation\n", + "and solve it using the Maxwell 2D DCConduction solver.\n", + "\n", + "Keywords: **Maxwell 2D**, **DXF import**, **material sweep**, **expression cache**." + ] + }, + { + "cell_type": "markdown", + "id": "17b2dda3", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6b2f89b", + "metadata": {}, + "outputs": [], + "source": [ + "import os.path\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7faf887", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.visualization.plot.pdf import AnsysReport" + ] + }, + { + "cell_type": "markdown", + "id": "023feb2c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d097ce2e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False\n", + "NUM_CORES = 4" + ] + }, + { + "cell_type": "markdown", + "id": "89d5b223", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33f96022", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "6921da36", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D after first setting up the project and design names,\n", + "the solver, and the version. The following code also creates an instance of the\n", + "``Maxwell2d`` class named ``m2d``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efa3bb20", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"M2D_DC_Conduction.aedt\")\n", + "m2d = ansys.aedt.core.Maxwell2d(\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " close_on_exit=True,\n", + " solution_type=\"DCConduction\",\n", + " project=project_name,\n", + " design=\"Ansys_resistor\",\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e801b521", + "metadata": {}, + "source": [ + "## Import geometry as a DXF file\n", + "\n", + "You can test importing a DXF or a Parasolid file by commenting and uncommenting\n", + "the following lines.\n", + "Importing DXF files only works in graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a784cace", + "metadata": {}, + "outputs": [], + "source": [ + "# DXFPath = ansys.aedt.core.downloads.download_file(\"dxf\", \"Ansys_logo_2D.dxf\")\n", + "# dxf_layers = m2d.get_dxf_layers(DXFPath)\n", + "# m2d.import_dxf(DXFPath, dxf_layers, scale=1E-05)\n", + "\n", + "parasolid_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"x_t\", name=\"Ansys_logo_2D.x_t\", destination=temp_folder.name\n", + ")\n", + "m2d.modeler.import_3d_cad(parasolid_path)" + ] + }, + { + "cell_type": "markdown", + "id": "65b7df64", + "metadata": {}, + "source": [ + "## Define variables\n", + "\n", + "Define the conductor thickness in the z-direction, the material array with four materials,\n", + "and the material index referring to the material array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b886ac0", + "metadata": {}, + "outputs": [], + "source": [ + "m2d[\"MaterialThickness\"] = \"5mm\"\n", + "m2d[\"ConductorMaterial\"] = '[\"Copper\", \"Aluminum\", \"silver\", \"gold\"]'\n", + "material_index = 0\n", + "m2d[\"MaterialIndex\"] = str(material_index)\n", + "no_materials = 4" + ] + }, + { + "cell_type": "markdown", + "id": "da07fdbd", + "metadata": {}, + "source": [ + "## Assign materials\n", + "\n", + "Voltage ports are defined as gold. The conductor\n", + "gets the material defined by the 0th entry of the material array." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a38abd80", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_material(assignment=[\"ANSYS_LOGO_2D_1\", \"ANSYS_LOGO_2D_2\"], material=\"gold\")\n", + "m2d.modeler[\"ANSYS_LOGO_2D_3\"].material_name = \"ConductorMaterial[MaterialIndex]\"" + ] + }, + { + "cell_type": "markdown", + "id": "1daa8aaa", + "metadata": {}, + "source": [ + "## Assign voltages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b66b6e6", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_voltage(assignment=[\"ANSYS_LOGO_2D_1\"], amplitude=1, name=\"1V\")\n", + "m2d.assign_voltage(assignment=[\"ANSYS_LOGO_2D_2\"], amplitude=0, name=\"0V\")" + ] + }, + { + "cell_type": "markdown", + "id": "3e7af535", + "metadata": {}, + "source": [ + "## Set up conductance calculation\n", + "\n", + "``1V`` is the source. ``0V`` is the ground." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f892a76e", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_matrix(assignment=[\"1V\"], group_sources=[\"0V\"], matrix_name=\"Matrix1\")" + ] + }, + { + "cell_type": "markdown", + "id": "4a58524b", + "metadata": {}, + "source": [ + "## Assign mesh operation\n", + "\n", + "Assign three millimeters as the maximum length." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6720b44", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_length_mesh(\n", + " assignment=[\"ANSYS_LOGO_2D_3\"],\n", + " name=\"conductor\",\n", + " maximum_length=3,\n", + " maximum_elements=None,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1a6a438d", + "metadata": {}, + "source": [ + "## Create simulation setup and enable expression cache\n", + "\n", + "Create the simulation setup with a minimum of four adaptive passes to ensure convergence.\n", + "Enable the expression cache to observe the convergence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f8bb888", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m2d.create_setup(name=\"Setup1\", MinimumPasses=4)\n", + "setup.enable_expression_cache(\n", + " report_type=\"DCConduction\",\n", + " expressions=\"1/Matrix1.G(1V,1V)/MaterialThickness\",\n", + " isconvergence=True,\n", + " conv_criteria=1,\n", + " use_cache_for_freq=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7e70cc22", + "metadata": {}, + "source": [ + "## Analyze setup\n", + "\n", + "Run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b84dccb5", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.analyze(setup=setup.name, cores=NUM_CORES, use_auto_settings=False)" + ] + }, + { + "cell_type": "markdown", + "id": "97ce22e3", + "metadata": {}, + "source": [ + "## Create parametric sweep\n", + "\n", + "Create a parametric sweep to sweep all the entries in the material array.\n", + "Save fields and mesh. Use the mesh for all the materials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c6b8c17", + "metadata": {}, + "outputs": [], + "source": [ + "sweep = m2d.parametrics.add(\n", + " variable=\"MaterialIndex\",\n", + " start_point=0,\n", + " end_point=no_materials - 1,\n", + " step=1,\n", + " variation_type=\"LinearStep\",\n", + " name=\"MaterialSweep\",\n", + ")\n", + "sweep[\"SaveFields\"] = True\n", + "sweep[\"CopyMesh\"] = True\n", + "sweep[\"SolveWithCopiedMeshOnly\"] = True\n", + "sweep.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "9337421c", + "metadata": {}, + "source": [ + "## Output variable\n", + "\n", + "Define output variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ddefd97", + "metadata": {}, + "outputs": [], + "source": [ + "expression = \"1/Matrix1.G(1V,1V)/MaterialThickness\"\n", + "m2d.ooutput_variable.CreateOutputVariable(\n", + " \"out1\", expression, m2d.nominal_sweep, \"DCConduction\", []\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "63e8aaa2", + "metadata": {}, + "source": [ + "## Create report\n", + "\n", + "Create a material resistance versus material index report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31db3050", + "metadata": {}, + "outputs": [], + "source": [ + "variations = {\"MaterialIndex\": [\"All\"], \"MaterialThickness\": [\"Nominal\"]}\n", + "report = m2d.post.create_report(\n", + " expressions=\"out1\",\n", + " primary_sweep_variable=\"MaterialIndex\",\n", + " report_category=\"DCConduction\",\n", + " plot_type=\"Data Table\",\n", + " variations=variations,\n", + " plot_name=\"Resistance vs. Material\",\n", + ")\n", + "\n", + "# ## Get solution data\n", + "#\n", + "# Get solution data using the ``report``` object to get resistance values\n", + "# and plot data outside AEDT.\n", + "\n", + "data = report.get_solution_data()\n", + "resistance = data.data_magnitude()\n", + "material_index = data.primary_sweep_values\n", + "data.primary_sweep = \"MaterialIndex\"\n", + "data.plot(snapshot_path=os.path.join(temp_folder.name, \"M2D_DCConduction.jpg\"))\n", + "\n", + "# ## Create material index versus resistance table\n", + "#\n", + "# Create material index versus resistance table to use in the PDF report generator.\n", + "# Create ``colors`` table to customize each row of the material index versus resistance table.\n", + "\n", + "material_index_vs_resistance = [[\"Material\", \"Resistance\"]]\n", + "colors = [[(255, 255, 255), (0, 255, 0)]]\n", + "for i in range(len(data.primary_sweep_values)):\n", + " material_index_vs_resistance.append(\n", + " [str(data.primary_sweep_values[i]), str(resistance[i])]\n", + " )\n", + " colors.append([None, None])" + ] + }, + { + "cell_type": "markdown", + "id": "ae3dcc12", + "metadata": {}, + "source": [ + "## Overlay fields\n", + "\n", + "Plot the electric field and current density on the conductor surface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0a1b508", + "metadata": {}, + "outputs": [], + "source": [ + "conductor_surface = m2d.modeler[\"ANSYS_LOGO_2D_3\"].faces\n", + "plot1 = m2d.post.create_fieldplot_surface(\n", + " assignment=conductor_surface, quantity=\"Mag_E\", plot_name=\"Electric Field\"\n", + ")\n", + "plot2 = m2d.post.create_fieldplot_surface(\n", + " assignment=conductor_surface, quantity=\"Mag_J\", plot_name=\"Current Density\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "116b2bd3", + "metadata": {}, + "source": [ + "## Overlay fields using PyVista\n", + "\n", + "Plot electric field using PyVista and save to an image file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "494b58aa", + "metadata": {}, + "outputs": [], + "source": [ + "py_vista_plot = m2d.post.plot_field(\n", + " quantity=\"Mag_E\", assignment=conductor_surface, plot_cad_objs=False, show=False\n", + ")\n", + "py_vista_plot.isometric_view = False\n", + "py_vista_plot.camera_position = [0, 0, 7]\n", + "py_vista_plot.focal_point = [0, 0, 0]\n", + "py_vista_plot.roll_angle = 0\n", + "py_vista_plot.elevation_angle = 0\n", + "py_vista_plot.azimuth_angle = 0\n", + "py_vista_plot.plot(os.path.join(temp_folder.name, \"mag_E.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "f44c6123", + "metadata": {}, + "source": [ + "## Plot field animation\n", + "\n", + "Plot current density verus the material index." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c94a8083", + "metadata": {}, + "outputs": [], + "source": [ + "animated_plot = m2d.post.plot_animated_field(\n", + " quantity=\"Mag_J\",\n", + " assignment=conductor_surface,\n", + " export_path=temp_folder.name,\n", + " variation_variable=\"MaterialIndex\",\n", + " variations=[0, 1, 2, 3],\n", + " show=False,\n", + " export_gif=False,\n", + " log_scale=True,\n", + ")\n", + "animated_plot.isometric_view = False\n", + "animated_plot.camera_position = [0, 0, 7]\n", + "animated_plot.focal_point = [0, 0, 0]\n", + "animated_plot.roll_angle = 0\n", + "animated_plot.elevation_angle = 0\n", + "animated_plot.azimuth_angle = 0\n", + "animated_plot.animate()" + ] + }, + { + "cell_type": "markdown", + "id": "4e15f1f8", + "metadata": {}, + "source": [ + "## Export model picture" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c293dd4e", + "metadata": {}, + "outputs": [], + "source": [ + "model_picture = m2d.post.export_model_picture()" + ] + }, + { + "cell_type": "markdown", + "id": "056bf5ea", + "metadata": {}, + "source": [ + "## Generate PDF report\n", + "\n", + "Generate a PDF report with the output of the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fbb3681b", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report = AnsysReport(\n", + " project_name=m2d.project_name, design_name=m2d.design_name, version=AEDT_VERSION\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4ea30943", + "metadata": {}, + "source": [ + "Customize the text font." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b5dcb17", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.report_specs.font = \"times\"\n", + "pdf_report.report_specs.text_font_size = 10" + ] + }, + { + "cell_type": "markdown", + "id": "8c843d48", + "metadata": {}, + "source": [ + "Create the report" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48b7ec5f", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.create()" + ] + }, + { + "cell_type": "markdown", + "id": "cf2fb2ee", + "metadata": {}, + "source": [ + "Add project's design information to the report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b47a5ef5", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_project_info(m2d)" + ] + }, + { + "cell_type": "markdown", + "id": "870c88bc", + "metadata": {}, + "source": [ + "Add the model picture in a new chapter. Then, add text." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95c59bc9", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_chapter(\"Model Picture\")\n", + "pdf_report.add_text(\"This section contains the model picture.\")\n", + "pdf_report.add_image(path=model_picture, caption=\"Model Picture\", width=80, height=60)" + ] + }, + { + "cell_type": "markdown", + "id": "9380a0ef", + "metadata": {}, + "source": [ + "Add field overlay plots in a new chapter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96fe443a", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_chapter(\"Field overlay\")\n", + "pdf_report.add_sub_chapter(\"Plots\")\n", + "pdf_report.add_text(\"This section contains the fields overlay.\")\n", + "pdf_report.add_image(\n", + " os.path.join(temp_folder.name, \"mag_E.jpg\"), caption=\"Mag E\", width=120, height=80\n", + ")\n", + "pdf_report.add_page_break()" + ] + }, + { + "cell_type": "markdown", + "id": "e0ee66f6", + "metadata": {}, + "source": [ + "Add a new section to display results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7516835b", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_section()\n", + "pdf_report.add_chapter(\"Results\")\n", + "pdf_report.add_sub_chapter(\"Resistance vs. Material\")\n", + "pdf_report.add_text(\"This section contains resistance versus material data.\")\n", + "# Aspect ratio is automatically calculated if only width is provided\n", + "pdf_report.add_image(os.path.join(temp_folder.name, \"M2D_DCConduction.jpg\"), width=130)" + ] + }, + { + "cell_type": "markdown", + "id": "f5a4c84c", + "metadata": {}, + "source": [ + "Add a new subchapter to display resistance data from the previously created table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "582c48da", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_sub_chapter(\"Resistance data table\")\n", + "pdf_report.add_text(\"This section contains resistance data.\")\n", + "pdf_report.add_table(\n", + " title=\"Resistance Data\",\n", + " content=material_index_vs_resistance,\n", + " formatting=colors,\n", + " col_widths=[75, 100],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "671c32c5", + "metadata": {}, + "source": [ + "Add a table of contents and save the PDF." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36dd9b08", + "metadata": {}, + "outputs": [], + "source": [ + "pdf_report.add_toc()\n", + "pdf_report.save_pdf(temp_folder.name, \"AEDT_Results.pdf\")" + ] + }, + { + "cell_type": "markdown", + "id": "85aae26a", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4b214c7", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b3fadae4", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fa4d0ba", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/dynamic_rom.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/dynamic_rom.ipynb.txt new file mode 100644 index 00000000..2130bd92 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/dynamic_rom.ipynb.txt @@ -0,0 +1,574 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "84f30475", + "metadata": {}, + "source": [ + "# Dynamic ROM\n", + "\n", + "This example shows how to use PyAEDT to create a dynamic reduced order model (ROM)\n", + "in Twin Builder and run a Twin Builder time-domain simulation.\n", + "\n", + "> **Note:** This example uses functionality only available in Twin\n", + "> Builder 2023 R2 and later.\n", + "\n", + "Keywords: **Twin Builder**, **Dynamic ROM**." + ] + }, + { + "cell_type": "markdown", + "id": "95b9bc9a", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92df96b7", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import shutil\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8983be1", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "308ec568", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e64556e1", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "a675fb27", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b988bde8", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "7fae2569", + "metadata": {}, + "source": [ + "## Set up input data\n", + "\n", + "Define the file name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09e3d7fb", + "metadata": {}, + "outputs": [], + "source": [ + "source_snapshot_data_zipfilename = \"Ex1_Mechanical_DynamicRom.zip\"\n", + "source_build_conf_file = \"dynarom_build.conf\"" + ] + }, + { + "cell_type": "markdown", + "id": "ee48db6b", + "metadata": {}, + "source": [ + "Download data from the ``example_data`` repository." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a93b3116", + "metadata": {}, + "outputs": [], + "source": [ + "_ = ansys.aedt.core.downloads.download_twin_builder_data(\n", + " file_name=source_snapshot_data_zipfilename,\n", + " force_download=True,\n", + " destination=temp_folder.name,\n", + ")\n", + "source_data_folder = ansys.aedt.core.downloads.download_twin_builder_data(\n", + " source_build_conf_file, True, temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d314422c", + "metadata": {}, + "source": [ + "Toggle these for local testing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ed7fc9e", + "metadata": {}, + "outputs": [], + "source": [ + "data_folder = os.path.join(source_data_folder, \"Ex03\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5323b769", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "# Unzip training data and config file\n", + "ansys.aedt.core.downloads.unzip(\n", + " os.path.join(source_data_folder, source_snapshot_data_zipfilename), data_folder\n", + ")\n", + "shutil.copyfile(\n", + " os.path.join(source_data_folder, source_build_conf_file),\n", + " os.path.join(data_folder, source_build_conf_file),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "06d1d6e2", + "metadata": {}, + "source": [ + "## Launch Twin Builder and build ROM component\n", + "\n", + "Launch Twin Builder using an implicit declaration and add a new design with\n", + "the default setup for building the dynamic ROM component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d751fa95", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"dynamic_rom.aedt\")\n", + "tb = ansys.aedt.core.TwinBuilder(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e80b797b", + "metadata": {}, + "source": [ + "## Configure AEDT\n", + "\n", + "> **Note:** Only run the following cell if AEDT is not configured to run Twin Builder.\n", + ">\n", + "> The following cell configures AEDT and the schematic editor\n", + "> to use the ``Twin Builder`` configuration.\n", + "> The dynamic ROM feature is only available with a Twin Builder license.\n", + "> A cell at the end of this example restores the AEDT configuration. If your\n", + "> environment is set up to use the ``Twin Builder`` configuration, you do not\n", + "> need to run these code blocks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a74fdfdc", + "metadata": {}, + "outputs": [], + "source": [ + "current_desktop_config = tb._odesktop.GetDesktopConfiguration()\n", + "current_schematic_environment = tb._odesktop.GetSchematicEnvironment()\n", + "tb._odesktop.SetDesktopConfiguration(\"Twin Builder\")\n", + "tb._odesktop.SetSchematicEnvironment(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaef81aa", + "metadata": {}, + "outputs": [], + "source": [ + "# Get the dynamic ROM builder object.\n", + "rom_manager = tb._odesign.GetROMManager()\n", + "dynamic_rom_builder = rom_manager.GetDynamicROMBuilder()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a4393b7", + "metadata": {}, + "outputs": [], + "source": [ + "# Build the dynamic ROM with the specified configuration file.\n", + "conf_file_path = os.path.join(data_folder, source_build_conf_file)\n", + "dynamic_rom_builder.Build(conf_file_path.replace(\"\\\\\", \"/\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ade2d0dc", + "metadata": {}, + "outputs": [], + "source": [ + "# Test if the ROM was created successfully\n", + "dynamic_rom_path = os.path.join(data_folder, \"DynamicRom.dyn\")\n", + "if os.path.exists(dynamic_rom_path):\n", + " tb._odesign.AddMessage(\n", + " \"Info\", \"path exists: {}\".format(dynamic_rom_path.replace(\"\\\\\", \"/\")), \"\"\n", + " )\n", + "else:\n", + " tb._odesign.AddMessage(\n", + " \"Info\", \"path does not exist: {}\".format(dynamic_rom_path), \"\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f20a6e64", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "# Create the ROM component definition in Twin Builder.\n", + "rom_manager.CreateROMComponent(dynamic_rom_path.replace(\"\\\\\", \"/\"), \"dynarom\")" + ] + }, + { + "cell_type": "markdown", + "id": "0817ee69", + "metadata": {}, + "source": [ + "## Create schematic\n", + "\n", + "Place components to create a schematic." + ] + }, + { + "cell_type": "markdown", + "id": "1ef2bd5f", + "metadata": {}, + "source": [ + "Define the grid distance for ease in calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7078b06", + "metadata": {}, + "outputs": [], + "source": [ + "G = 0.00254" + ] + }, + { + "cell_type": "markdown", + "id": "2cfd5d59", + "metadata": {}, + "source": [ + "Place a dynamic ROM component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f486ffae", + "metadata": {}, + "outputs": [], + "source": [ + "rom1 = tb.modeler.schematic.create_component(\"ROM1\", \"\", \"dynarom\", [36 * G, 28 * G])" + ] + }, + { + "cell_type": "markdown", + "id": "d09b4015", + "metadata": {}, + "source": [ + "Place two excitation sources." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef5a3127", + "metadata": {}, + "outputs": [], + "source": [ + "source1 = tb.modeler.schematic.create_periodic_waveform_source(\n", + " None, \"PULSE\", 190, 0.002, \"300deg\", 210, 0, [20 * G, 29 * G]\n", + ")\n", + "source2 = tb.modeler.schematic.create_periodic_waveform_source(\n", + " None, \"PULSE\", 190, 0.002, \"300deg\", 210, 0, [20 * G, 25 * G]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f9dfa4ea", + "metadata": {}, + "source": [ + "Connect components with wires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7e541f1", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire([[22 * G, 29 * G], [33 * G, 29 * G]])\n", + "tb.modeler.schematic.create_wire(\n", + " [[22 * G, 25 * G], [30 * G, 25 * G], [30 * G, 28 * G], [33 * G, 28 * G]]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "477a1655", + "metadata": {}, + "outputs": [], + "source": [ + "# Zoom to fit the schematic.\n", + "tb.modeler.zoom_to_fit()" + ] + }, + { + "cell_type": "markdown", + "id": "67a6e82a", + "metadata": {}, + "source": [ + "## Parametrize transient setup\n", + "\n", + "Parametrize the default transient setup by setting the end time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "478d3662", + "metadata": {}, + "outputs": [], + "source": [ + "tb.set_end_time(\"1000s\")\n", + "tb.set_hmin(\"1s\")\n", + "tb.set_hmax(\"1s\")" + ] + }, + { + "cell_type": "markdown", + "id": "bb7f25ed", + "metadata": {}, + "source": [ + "## Solve transient setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb7480cf", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "tb.analyze_setup(\"TR\", cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "6b79ebdb", + "metadata": {}, + "source": [ + "## Get report data and plot using Matplotlib\n", + "\n", + "Get report data and plot it using Matplotlib. The following code gets and plots\n", + "the values for the voltage on the pulse voltage source and the values for the\n", + "output of the dynamic ROM." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "796ff77a", + "metadata": {}, + "outputs": [], + "source": [ + "input_excitation = \"PULSE1.VAL\"\n", + "x = tb.post.get_solution_data(input_excitation, \"TR\", \"Time\")\n", + "plt.plot(x.intrinsics[\"Time\"], x.data_real(input_excitation))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4bc2577", + "metadata": {}, + "outputs": [], + "source": [ + "output_temperature = \"ROM1.Temperature_history\"\n", + "x = tb.post.get_solution_data(output_temperature, \"TR\", \"Time\")\n", + "plt.plot(x.intrinsics[\"Time\"], x.data_real(output_temperature))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfb938f3", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "plt.grid()\n", + "plt.xlabel(\"Time\")\n", + "plt.ylabel(\"Temperature History Variation with Input Temperature Pulse\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "9674423c", + "metadata": {}, + "source": [ + "## Close Twin Builder\n", + "\n", + "After the simulation is completed, you can close Twin Builder or release it.\n", + "All methods provide for saving the project before closing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b9eb564", + "metadata": {}, + "outputs": [], + "source": [ + "# Clean up the downloaded data.\n", + "shutil.rmtree(source_data_folder)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fa4a3bb", + "metadata": {}, + "outputs": [], + "source": [ + "# Restore the earlier AEDT configuration and schematic environment.\n", + "tb._odesktop.SetDesktopConfiguration(current_desktop_config)\n", + "tb._odesktop.SetSchematicEnvironment(current_schematic_environment)" + ] + }, + { + "cell_type": "markdown", + "id": "f7ce9fa3", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abad4f4c", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "94a3ffe6", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "528012e1", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/index.rst.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/index.rst.txt new file mode 100644 index 00000000..5c2b0e01 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/index.rst.txt @@ -0,0 +1,83 @@ +Twin Builder +~~~~~~~~~~~~ + +These examples use PyAEDT to show some Twin Builder applications. + +.. grid:: 2 + + .. grid-item-card:: RC circuit design analysis + :padding: 2 2 2 2 + :link: rc_circuit + :link-type: doc + + .. image:: _static/rc.png + :alt: TB RC + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Twin Builder design and run a Twin Builder time-domain simulation. + + .. grid-item-card:: Wiring of a rectifier with a capacitor filter + :padding: 2 2 2 2 + :link: rectifier + :link-type: doc + + .. image:: _static/rectifier_response.png + :alt: TB Rectifier response + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Twin Builder design and run a Twin Builder time-domain simulation. + + + .. grid-item-card:: Static ROM + :padding: 2 2 2 2 + :link: static_rom + :link-type: doc + + .. image:: _static/static_rom.png + :alt: Static ROM + :width: 250px + :height: 200px + :align: center + + This example shows how to create a static reduced order model (ROM) in Twin Builder and run a transient simulation. + + .. grid-item-card:: Dynamic ROM + :padding: 2 2 2 2 + :link: dynamic_rom + :link-type: doc + + .. image:: _static/dynamic_rom_plot.png + :alt: Dynamic ROM plot + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a dynamic reduced order model (ROM) in Twin Builder and run a Twin Builder time-domain simulation. + + .. grid-item-card:: LTI ROM + :padding: 2 2 2 2 + :link: lti_rom_sml + :link-type: doc + + .. image:: _static/lti_rom.png + :alt: LTI ROM plot + :width: 250px + :height: 200px + :align: center + + This example shows how you can use PyAEDT to create a Linear Time Invariant (LTI) ROM in Twin Builder + and run a Twin Builder time-domain simulation. + + + .. toctree:: + :hidden: + + rc_circuit + rectifier + static_rom + dynamic_rom + lti_rom_sml diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/lti_rom_sml.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/lti_rom_sml.ipynb.txt new file mode 100644 index 00000000..e667ed72 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/lti_rom_sml.ipynb.txt @@ -0,0 +1,712 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "70b877f9", + "metadata": {}, + "source": [ + "# LTI ROM creation and simulation" + ] + }, + { + "cell_type": "markdown", + "id": "9f380c5a", + "metadata": {}, + "source": [ + "This example shows how you can use PyAEDT to create a Linear Time Invariant (LTI) ROM in Twin Builder\n", + "and run a Twin Builder time-domain simulation. Inputs data are defined using Datapairs blocks with CSV files.\n", + "\n", + "Keywords: **Twin Builder**, **LTI**, **ROM**." + ] + }, + { + "cell_type": "markdown", + "id": "cffbc9fd", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fba9a745", + "metadata": {}, + "outputs": [], + "source": [ + "import datetime\n", + "import os\n", + "import subprocess\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e72bce9a", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from ansys.aedt.core import TwinBuilder, downloads\n", + "from ansys.aedt.core.application.variables import CSVDataset" + ] + }, + { + "cell_type": "markdown", + "id": "f1bcce4a", + "metadata": {}, + "source": [ + "Define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb3d9ddb", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "6278cf72", + "metadata": {}, + "source": [ + "## Set paths and define input files and variables\n", + "\n", + "Set paths." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ce8feea", + "metadata": {}, + "outputs": [], + "source": [ + "training_data_folder = \"LTI_training_data.zip\"\n", + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")\n", + "input_dir = downloads.download_twin_builder_data(\n", + " training_data_folder, True, temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "eec8c219", + "metadata": {}, + "source": [ + "Download data from example_data repository" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91dfd828", + "metadata": {}, + "outputs": [], + "source": [ + "data_folder = os.path.join(input_dir, \"LTI_training\")" + ] + }, + { + "cell_type": "markdown", + "id": "18084590", + "metadata": {}, + "source": [ + "Unzip training data and parse ports names" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34e1b548", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "downloads.unzip(os.path.join(input_dir, training_data_folder), data_folder)\n", + "ports_names_file = \"Input_PortNames.txt\"" + ] + }, + { + "cell_type": "markdown", + "id": "34dfe7fd", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Get ports information from file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ae67acc", + "metadata": {}, + "outputs": [], + "source": [ + "def get_ports_info(ports_file):\n", + " with open(ports_file, \"r\") as PortNameFile:\n", + " res = []\n", + " line = PortNameFile.readline()\n", + " line_list = list(line.split())\n", + " for i in range(len(line_list)):\n", + " res.append(\"Input\" + str(i + 1) + \"_\" + line_list[i])\n", + "\n", + " line = PortNameFile.readline()\n", + " line_list = list(line.split())\n", + " for i in range(len(line_list)):\n", + " res.append(\"Output\" + str(i + 1) + \"_\" + line_list[i])\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52876951", + "metadata": {}, + "outputs": [], + "source": [ + "pin_names = get_ports_info(os.path.join(data_folder, ports_names_file))" + ] + }, + { + "cell_type": "markdown", + "id": "99089218", + "metadata": {}, + "source": [ + "## Launch Twin Builder\n", + "\n", + "Launch Twin Builder using an implicit declaration and add a new design with\n", + "the default setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae1fe3c1", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"LTI_ROM.aedt\")\n", + "tb = TwinBuilder(\n", + " project=project_name, version=AEDT_VERSION, non_graphical=NG_MODE, new_desktop=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "de576662", + "metadata": {}, + "source": [ + "## Build the LTI ROM with specified configuration file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66eab0e9", + "metadata": {}, + "outputs": [], + "source": [ + "install_dir = tb.odesktop.GetRegistryString(\"Desktop/InstallationDirectory\")\n", + "fitting_exe = os.path.join(install_dir, \"FittingTool.exe\")\n", + "path = '\"' + fitting_exe + '\"' + \" \" + '\"t\"' + \" \" + '\"' + data_folder + '\"'\n", + "process = subprocess.Popen(\n", + " path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE\n", + ")\n", + "tb.logger.info(\"Fitting the LTI ROM training data\")\n", + "exec = True\n", + "startTime = datetime.datetime.now()\n", + "execTime = 0.0\n", + "while (\n", + " exec and execTime < 60.0\n", + "): # limiting the fitting process execution time to 1 minute\n", + " out, err = process.communicate()\n", + " execTime = (datetime.datetime.now() - startTime).total_seconds()\n", + " if \"An LTI ROM has been generated\" in str(out):\n", + " process.terminate()\n", + " exec = False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb92499f", + "metadata": {}, + "outputs": [], + "source": [ + "rom_file = \"\"\n", + "model_name_sml = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6769f0ad", + "metadata": {}, + "outputs": [], + "source": [ + "for i in os.listdir(data_folder):\n", + " if i.endswith(\".sml\"):\n", + " model_name_sml = i.split(\".\")[0]\n", + " rom_file = os.path.join(data_folder, i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e75fa92b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "if os.path.exists(rom_file):\n", + " tb.logger.info(\"Built intermediate ROM file successfully at: %s\", rom_file)\n", + "else:\n", + " tb.logger.info(\"ROM file does not exist at the expected location : %s\", rom_file)" + ] + }, + { + "cell_type": "markdown", + "id": "1d2fd47b", + "metadata": {}, + "source": [ + "## Import the ROM component model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65f43096", + "metadata": {}, + "outputs": [], + "source": [ + "is_created = tb.modeler.schematic.create_component_from_sml(\n", + " input_file=rom_file, model=model_name_sml, pins_names=pin_names\n", + ")\n", + "os.remove(rom_file)\n", + "tb.logger.info(\"LTI ROM model successfully imported.\")" + ] + }, + { + "cell_type": "markdown", + "id": "b55f110d", + "metadata": {}, + "source": [ + "## Import the ROM component model in Twin Builder\n", + "\n", + "Place components to create a schematic." + ] + }, + { + "cell_type": "markdown", + "id": "78c2cf60", + "metadata": {}, + "source": [ + "Define the grid distance for ease in calculations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfe46ff5", + "metadata": {}, + "outputs": [], + "source": [ + "grid_distance = 0.00254" + ] + }, + { + "cell_type": "markdown", + "id": "c0f13993", + "metadata": {}, + "source": [ + "Place the ROM component" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "120ab1e5", + "metadata": {}, + "outputs": [], + "source": [ + "rom1 = tb.modeler.schematic.create_component(\n", + " \"ROM1\", \"\", model_name_sml, [36 * grid_distance, 28 * grid_distance]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "619bc95d", + "metadata": {}, + "source": [ + "Place datapairs blocks for inputs definition" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "639ed58f", + "metadata": {}, + "outputs": [], + "source": [ + "source1 = tb.modeler.schematic.create_component(\n", + " \"source1\",\n", + " \"\",\n", + " \"Simplorer Elements\\\\Basic Elements\\\\Tools\\\\Time Functions:DATAPAIRS\",\n", + " [20 * grid_distance, 29 * grid_distance],\n", + ")\n", + "source2 = tb.modeler.schematic.create_component(\n", + " \"source2\",\n", + " \"\",\n", + " \"Simplorer Elements\\\\Basic Elements\\\\Tools\\\\Time Functions:DATAPAIRS\",\n", + " [20 * grid_distance, 25 * grid_distance],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4a51a2ef", + "metadata": {}, + "source": [ + "Import Datasets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b49081b2", + "metadata": {}, + "outputs": [], + "source": [ + "data1 = CSVDataset(os.path.join(data_folder, \"data1.csv\"))\n", + "data2 = CSVDataset(os.path.join(data_folder, \"data2.csv\"))\n", + "dataset1 = tb.create_dataset(\"data1\", data1.data[\"time\"], data1.data[\"input1\"])\n", + "dataset2 = tb.create_dataset(\"data2\", data2.data[\"time\"], data2.data[\"input2\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c1e946b", + "metadata": {}, + "outputs": [], + "source": [ + "source1.parameters[\"CH_DATA\"] = dataset1.name\n", + "source2.parameters[\"CH_DATA\"] = dataset2.name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77c2e2b9", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.update_quantity_value(source1.composed_name, \"PERIO\", \"0\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3336815e", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.update_quantity_value(\n", + " source1.composed_name, \"TPERIO\", \"Tend+1\", \"s\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e160a95", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.update_quantity_value(source2.composed_name, \"PERIO\", \"0\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17be058e", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.update_quantity_value(\n", + " source2.composed_name, \"TPERIO\", \"Tend+1\", \"s\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "97e81717", + "metadata": {}, + "source": [ + "Connect components with wires" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2554d7c9", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire(\n", + " points=[source1.pins[0].location, rom1.pins[0].location]\n", + ")\n", + "tb.modeler.schematic.create_wire(\n", + " points=[source2.pins[0].location, rom1.pins[1].location]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "342d052a", + "metadata": {}, + "source": [ + "Zoom to fit the schematic" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "044d01e6", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.zoom_to_fit()" + ] + }, + { + "cell_type": "markdown", + "id": "f057bb32", + "metadata": {}, + "source": [ + "## Parametrize transient setup\n", + "\n", + "Parametrize the default transient setup by setting the end time and minimum/maximum time steps." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf51e0c3", + "metadata": {}, + "outputs": [], + "source": [ + "tb.set_end_time(\"700s\")\n", + "tb.set_hmin(\"0.001s\")\n", + "tb.set_hmax(\"1s\")" + ] + }, + { + "cell_type": "markdown", + "id": "9f740981", + "metadata": {}, + "source": [ + "## Solve transient setup\n", + "\n", + "Solve the transient setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "977110ea", + "metadata": {}, + "outputs": [], + "source": [ + "tb.analyze_setup(\"TR\")" + ] + }, + { + "cell_type": "markdown", + "id": "81342fc0", + "metadata": {}, + "source": [ + "## Get report data and plot using Matplotlib\n", + "\n", + "Get report data and plot it using Matplotlib. The following code gets and plots\n", + "the values for the inputs and outputs of the LTI ROM." + ] + }, + { + "cell_type": "markdown", + "id": "e339034c", + "metadata": {}, + "source": [ + "Units used are based on AEDT default units." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0288a3c8", + "metadata": {}, + "outputs": [], + "source": [ + "variables_postprocessing = []\n", + "pin_names_str = \",\".join(pin_names)\n", + "rom_pins = pin_names_str.lower().split(\",\")\n", + "fig, ax = plt.subplots(ncols=1, nrows=2, figsize=(18, 7))\n", + "fig.subplots_adjust(hspace=0.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16642e38", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(0, 2):\n", + " variable = \"ROM1.\" + rom_pins[i]\n", + " x = tb.post.get_solution_data(variable, \"TR\", \"Time\")\n", + " ax[0].plot(\n", + " [el for el in x.intrinsics[\"Time\"]], x.data_real(variable), label=variable\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "673f4504", + "metadata": {}, + "outputs": [], + "source": [ + "ax[0].set_title(\"ROM inputs\")\n", + "ax[0].legend(loc=\"upper left\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb39f780", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(2, 4):\n", + " variable = \"ROM1.\" + rom_pins[i]\n", + " x = tb.post.get_solution_data(variable, \"TR\", \"Time\")\n", + " ax[1].plot(\n", + " [el for el in x.intrinsics[\"Time\"]], x.data_real(variable), label=variable\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5afc763", + "metadata": {}, + "outputs": [], + "source": [ + "ax[1].set_title(\"ROM outputs\")\n", + "ax[1].legend(loc=\"upper left\")" + ] + }, + { + "cell_type": "markdown", + "id": "40662e5c", + "metadata": {}, + "source": [ + "Show plot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffd316e2", + "metadata": {}, + "outputs": [], + "source": [ + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "5d6306b1", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130c3cf6", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()" + ] + }, + { + "cell_type": "markdown", + "id": "02ea83a2", + "metadata": {}, + "source": [ + "Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62a5f2d0", + "metadata": {}, + "outputs": [], + "source": [ + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "62c19223", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4cbb3de5", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/rc_circuit.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/rc_circuit.ipynb.txt new file mode 100644 index 00000000..63f1ce31 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/rc_circuit.ipynb.txt @@ -0,0 +1,313 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "31f24632", + "metadata": {}, + "source": [ + "# RC circuit design analysis\n", + "\n", + "This example shows how to use PyAEDT to create a Twin Builder design\n", + "and run a Twin Builder time-domain simulation.\n", + "\n", + "Keywords: **Twin Builder**, **RC**." + ] + }, + { + "cell_type": "markdown", + "id": "e836277b", + "metadata": {}, + "source": [ + "## Perform imports and define constantss\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78d3de34", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebba1cdf", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "c4f47e3f", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e955039", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "e2d7dce0", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1dbd972", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "33dd0c05", + "metadata": {}, + "source": [ + "## Launch Twin Builder\n", + "\n", + "Launch Twin Builder using an implicit declaration and add a new design with\n", + "a default setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39d8da01", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"rc_circuit.aedt\")\n", + "tb = ansys.aedt.core.TwinBuilder(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "tb.modeler.schematic_units = \"mil\"" + ] + }, + { + "cell_type": "markdown", + "id": "60f3d32a", + "metadata": {}, + "source": [ + "## Create components for RC circuit\n", + "\n", + "Create components for an RC circuit driven by a pulse voltage source.\n", + "Create components, such as a voltage source, resistor, and capacitor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccd46d3e", + "metadata": {}, + "outputs": [], + "source": [ + "source = tb.modeler.schematic.create_voltage_source(\"E1\", \"EPULSE\", 10, 10, [0, 0])\n", + "resistor = tb.modeler.schematic.create_resistor(\"R1\", 10000, [1000, 1000], 90)\n", + "capacitor = tb.modeler.schematic.create_capacitor(\"C1\", 1e-6, [2000, 0])" + ] + }, + { + "cell_type": "markdown", + "id": "1fdd190d", + "metadata": {}, + "source": [ + "## Create ground\n", + "\n", + "Create a ground, which is needed for an analog analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05b3d625", + "metadata": {}, + "outputs": [], + "source": [ + "gnd = tb.modeler.components.create_gnd([0, -1000])" + ] + }, + { + "cell_type": "markdown", + "id": "e4aacfe6", + "metadata": {}, + "source": [ + "## Connect components\n", + "\n", + "Connects components with pins." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bfd54086", + "metadata": {}, + "outputs": [], + "source": [ + "source.pins[1].connect_to_component(resistor.pins[0])\n", + "resistor.pins[1].connect_to_component(capacitor.pins[0])\n", + "capacitor.pins[1].connect_to_component(source.pins[0])\n", + "source.pins[0].connect_to_component(gnd.pins[0])" + ] + }, + { + "cell_type": "markdown", + "id": "177e01b6", + "metadata": {}, + "source": [ + "## Parametrize transient setup\n", + "\n", + "Parametrize the default transient setup by setting the end time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "abf75eb3", + "metadata": {}, + "outputs": [], + "source": [ + "tb.set_end_time(\"300ms\")" + ] + }, + { + "cell_type": "markdown", + "id": "620d1a99", + "metadata": {}, + "source": [ + "## Solve transient setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81c89f5d", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "tb.analyze_setup(\"TR\")" + ] + }, + { + "cell_type": "markdown", + "id": "66112f4c", + "metadata": {}, + "source": [ + "## Get report data and plot using Matplotlib\n", + "\n", + "Get report data and plot it using Matplotlib. The following code gets and plots\n", + "the values for the voltage on the pulse voltage source and the values for the\n", + "voltage on the capacitor in the RC circuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39ec0b3e", + "metadata": {}, + "outputs": [], + "source": [ + "E_Value = \"E1.V\"\n", + "C_Value = \"C1.V\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8515ba0", + "metadata": {}, + "outputs": [], + "source": [ + "x = tb.post.get_solution_data([E_Value, C_Value], \"TR\", \"Time\")\n", + "x.plot([E_Value, C_Value], x_label=\"Time\", y_label=\"Capacitor Voltage vs Input Pulse\")" + ] + }, + { + "cell_type": "markdown", + "id": "d24e80a5", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1144bea2", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "3a9215a2", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49c3ab93", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/rectifier.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/rectifier.ipynb.txt new file mode 100644 index 00000000..76cc1a53 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/rectifier.ipynb.txt @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9d7b9689", + "metadata": {}, + "source": [ + "# Wiring of a rectifier with a capacitor filter\n", + "\n", + "This example shows how to use PyAEDT to create a Twin Builder design\n", + "and run a Twin Builder time-domain simulation.\n", + "\n", + "\n", + "\n", + "Keywords: **Twin Builder**, **rectifier**, **filter**." + ] + }, + { + "cell_type": "markdown", + "id": "ea1941d3", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ce9562a", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c4aad6b", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "7d91b60a", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "777aaa5d", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "1c023d44", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5377fc0", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "5bd4939f", + "metadata": {}, + "source": [ + "## Launch Twin Builder\n", + "\n", + "Launch Twin Builder using an implicit declaration and add a new design with\n", + "the default setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a437cc2", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"TB_Rectifier_Demo.aedt\")\n", + "tb = ansys.aedt.core.TwinBuilder(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "30836100", + "metadata": {}, + "source": [ + "## Create components\n", + "\n", + "Place components for a bridge rectifier and a capacitor filter in the schematic editor.\n", + "\n", + "Specify the grid spacing to use for placement\n", + "of components in the schematic editor. Components are placed using the named\n", + "argument ``location`` as a list of ``[x, y]`` values in millimeters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b84c74f7", + "metadata": {}, + "outputs": [], + "source": [ + "G = 0.00254" + ] + }, + { + "cell_type": "markdown", + "id": "06329b98", + "metadata": {}, + "source": [ + "Create an AC sinosoidal voltage source." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a090f97", + "metadata": {}, + "outputs": [], + "source": [ + "source = tb.modeler.schematic.create_voltage_source(\n", + " \"V_AC\", \"ESINE\", 100, 50, location=[-1 * G, 0]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "624e7c13", + "metadata": {}, + "source": [ + "Place the four diodes of the bridge rectifier. The named argument ``angle`` is the rotation angle\n", + "of the component in radians." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3cb6ad0", + "metadata": {}, + "outputs": [], + "source": [ + "diode1 = tb.modeler.schematic.create_diode(\n", + " name=\"D1\", location=[10 * G, 6 * G], angle=270\n", + ")\n", + "diode2 = tb.modeler.schematic.create_diode(\n", + " name=\"D2\", location=[20 * G, 6 * G], angle=270\n", + ")\n", + "diode3 = tb.modeler.schematic.create_diode(\n", + " name=\"D3\", location=[10 * G, -4 * G], angle=270\n", + ")\n", + "diode4 = tb.modeler.schematic.create_diode(\n", + " name=\"D4\", location=[20 * G, -4 * G], angle=270\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f041e278", + "metadata": {}, + "source": [ + "Place a capacitor filter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e207269", + "metadata": {}, + "outputs": [], + "source": [ + "capacitor = tb.modeler.schematic.create_capacitor(\n", + " name=\"C_FILTER\", value=1e-6, location=[29 * G, -10 * G]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3fec16f5", + "metadata": {}, + "source": [ + "Place a load resistor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb8ee1f6", + "metadata": {}, + "outputs": [], + "source": [ + "resistor = tb.modeler.schematic.create_resistor(\n", + " name=\"RL\", value=100000, location=[39 * G, -10 * G]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5c529b13", + "metadata": {}, + "source": [ + "Place the ground component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b12e653a", + "metadata": {}, + "outputs": [], + "source": [ + "gnd = tb.modeler.components.create_gnd(location=[5 * G, -16 * G])" + ] + }, + { + "cell_type": "markdown", + "id": "6649d805", + "metadata": {}, + "source": [ + "## Connect components\n", + "\n", + "Connect components with wires, and connect the diode pins to create the bridge." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eba4a963", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire(\n", + " points=[diode1.pins[0].location, diode3.pins[0].location]\n", + ")\n", + "tb.modeler.schematic.create_wire(\n", + " points=[diode2.pins[1].location, diode4.pins[1].location]\n", + ")\n", + "tb.modeler.schematic.create_wire(\n", + " points=[diode1.pins[1].location, diode2.pins[0].location]\n", + ")\n", + "tb.modeler.schematic.create_wire(\n", + " points=[diode3.pins[1].location, diode4.pins[0].location]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0315c3a1", + "metadata": {}, + "source": [ + "Connect the voltage source to the bridge." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e66b4aea", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire(\n", + " points=[source.pins[1].location, [0, 10 * G], [15 * G, 10 * G], [15 * G, 5 * G]]\n", + ")\n", + "tb.modeler.schematic.create_wire(\n", + " points=[source.pins[0].location, [0, -10 * G], [15 * G, -10 * G], [15 * G, -5 * G]]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "18f35322", + "metadata": {}, + "source": [ + "Connect the filter capacitor and load resistor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6d8a571", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire(\n", + " points=[resistor.pins[0].location, [40 * G, 0], [22 * G, 0]]\n", + ")\n", + "tb.modeler.schematic.create_wire(points=[capacitor.pins[0].location, [30 * G, 0]])" + ] + }, + { + "cell_type": "markdown", + "id": "d388690b", + "metadata": {}, + "source": [ + "Add the ground connection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a7f6fd4", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire(\n", + " points=[resistor.pins[1].location, [40 * G, -15 * G], gnd.pins[0].location]\n", + ")\n", + "tb.modeler.schematic.create_wire(points=[capacitor.pins[1].location, [30 * G, -15 * G]])\n", + "tb.modeler.schematic.create_wire(points=[gnd.pins[0].location, [5 * G, 0], [8 * G, 0]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a2e5936", + "metadata": {}, + "outputs": [], + "source": [ + "# Zoom to fit the schematic\n", + "tb.modeler.zoom_to_fit()" + ] + }, + { + "cell_type": "markdown", + "id": "ced064f6", + "metadata": {}, + "source": [ + "The circuit schematic should now be visible in the Twin Builder\n", + "schematic editor and look like\n", + "the image shown at the beginning of the example.\n", + "\n", + "## Run the simulation\n", + "\n", + "Update the total time to be simulated and run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d06bf086", + "metadata": {}, + "outputs": [], + "source": [ + "tb.set_end_time(\"100ms\")\n", + "tb.analyze_setup(\"TR\")" + ] + }, + { + "cell_type": "markdown", + "id": "e92b5517", + "metadata": {}, + "source": [ + "## Get report data and plot using Matplotlib\n", + "\n", + "Get report data and plot it using Matplotlib. The following code gets and plots\n", + "the values for the voltage on the pulse voltage source and the values for the\n", + "voltage on the capacitor in the RC circuit." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00aa4d31", + "metadata": {}, + "outputs": [], + "source": [ + "src_name = source.InstanceName + \".V\"\n", + "x = tb.post.get_solution_data(src_name, \"TR\", \"Time\")\n", + "plt.plot(x.intrinsics[\"Time\"], x.data_real(src_name))\n", + "plt.grid()\n", + "plt.xlabel(\"Time\")\n", + "plt.ylabel(\"AC Voltage\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4a720f3", + "metadata": {}, + "outputs": [], + "source": [ + "r_voltage = resistor.InstanceName + \".V\"\n", + "x = tb.post.get_solution_data(r_voltage, \"TR\", \"Time\")\n", + "plt.plot(x.intrinsics[\"Time\"], x.data_real(r_voltage))\n", + "plt.grid()\n", + "plt.xlabel(\"Time\")\n", + "plt.ylabel(\"AC to DC Conversion using Rectifier\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a9b97c45", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8ac63c6", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e4353bb5", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa3e4bc0", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/general/twin_builder/static_rom.ipynb.txt b/version/dev/_sources/examples/low_frequency/general/twin_builder/static_rom.ipynb.txt new file mode 100644 index 00000000..de787456 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/general/twin_builder/static_rom.ipynb.txt @@ -0,0 +1,495 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1ff3e8c9", + "metadata": {}, + "source": [ + "# Static ROM\n", + "\n", + "This example shows how to create a static reduced order model (ROM)\n", + "in Twin Builder and run a transient simulation.\n", + "\n", + "> **Note:** This example uses functionality only available in Twin Builder 2024 R2 and later.\n", + "\n", + "Keywords: **Twin Builder**, **Static ROM**." + ] + }, + { + "cell_type": "markdown", + "id": "55ca97a7", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "488e3a7e", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import shutil\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e2f3b3e", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import TwinBuilder, downloads" + ] + }, + { + "cell_type": "markdown", + "id": "b08546a5", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b94040d4", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "14352858", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce07bb5f", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "6224aae4", + "metadata": {}, + "source": [ + "## Set up input data\n", + "\n", + "The following files are downloaded along with the\n", + "other project data used to run this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1670f528", + "metadata": {}, + "outputs": [], + "source": [ + "source_snapshot_data_zipfilename = \"Ex1_Fluent_StaticRom.zip\"\n", + "source_build_conf_file = \"SROMbuild.conf\"\n", + "source_props_conf_file = \"SROM_props.conf\"" + ] + }, + { + "cell_type": "markdown", + "id": "811878be", + "metadata": {}, + "source": [ + "## Download example data\n", + "\n", + "The following cell downloads the required files needed to run this example and\n", + "extracts them in a local folder named ``\"Ex04\"``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13f33106", + "metadata": {}, + "outputs": [], + "source": [ + "_ = downloads.download_twin_builder_data(\n", + " file_name=source_snapshot_data_zipfilename,\n", + " force_download=True,\n", + " destination=temp_folder.name,\n", + ")\n", + "\n", + "_ = downloads.download_twin_builder_data(source_build_conf_file, True, temp_folder.name)\n", + "source_data_folder = downloads.download_twin_builder_data(\n", + " source_props_conf_file, True, temp_folder.name\n", + ")\n", + "\n", + "# Target folder to extract project files.\n", + "data_folder = os.path.join(source_data_folder, \"Ex04\")\n", + "\n", + "# Unzip training data and config file\n", + "downloads.unzip(\n", + " os.path.join(source_data_folder, source_snapshot_data_zipfilename), data_folder\n", + ")\n", + "shutil.copyfile(\n", + " os.path.join(source_data_folder, source_build_conf_file),\n", + " os.path.join(data_folder, source_build_conf_file),\n", + ")\n", + "shutil.copyfile(\n", + " os.path.join(source_data_folder, source_props_conf_file),\n", + " os.path.join(data_folder, source_props_conf_file),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9c397e31", + "metadata": {}, + "source": [ + "## Launch Twin Builder and build ROM component\n", + "\n", + "Launch Twin Builder using an implicit declaration and add a new design with\n", + "the default setup for building the static ROM component." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44b82334", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"static_rom.aedt\")\n", + "tb = TwinBuilder(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "65741488", + "metadata": {}, + "source": [ + "## Configure AEDT\n", + "\n", + "> **Note:** Only run the following cell if AEDT is not configured to run Twin Builder.\n", + ">\n", + "> The following cell configures AEDT and the schematic editor\n", + "> to use the ``Twin Builder`` configuration.\n", + "> The Static ROM feature is only available with a Twin Builder license.\n", + "> A cell at the end of this example restores the AEDT configuration. If your\n", + "> environment is set up to use the ``Twin Builder`` configuration, you do not\n", + "> need to run these sections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4992fd9f", + "metadata": {}, + "outputs": [], + "source": [ + "current_desktop_config = tb._odesktop.GetDesktopConfiguration()\n", + "current_schematic_environment = tb._odesktop.GetSchematicEnvironment()\n", + "tb._odesktop.SetDesktopConfiguration(\"Twin Builder\")\n", + "tb._odesktop.SetSchematicEnvironment(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "048cbe65", + "metadata": {}, + "outputs": [], + "source": [ + "# Get the static ROM builder object.\n", + "rom_manager = tb._odesign.GetROMManager()\n", + "static_rom_builder = rom_manager.GetStaticROMBuilder()\n", + "\n", + "# Build the static ROM with the specified configuration file\n", + "confpath = os.path.join(data_folder, source_build_conf_file)\n", + "static_rom_builder.Build(confpath.replace(\"\\\\\", \"/\"))\n", + "\n", + "# Test if the ROM was created successfully.\n", + "static_rom_path = os.path.join(data_folder, \"StaticRom.rom\")\n", + "if os.path.exists(static_rom_path):\n", + " tb.logger.info(\"Built intermediate rom file successfully at: %s\", static_rom_path)\n", + "else:\n", + " tb.logger.error(\"Intermediate rom file not found at: %s\", static_rom_path)\n", + "\n", + "# Create the ROM component definition in Twin Builder.\n", + "rom_manager.CreateROMComponent(static_rom_path.replace(\"\\\\\", \"/\"), \"staticrom\")" + ] + }, + { + "cell_type": "markdown", + "id": "c9324193", + "metadata": {}, + "source": [ + "## Create schematic\n", + "\n", + "Place components to create the schematic." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2381f0fd", + "metadata": {}, + "outputs": [], + "source": [ + "# Define the grid distance for ease in calculations.\n", + "G = 0.00254\n", + "\n", + "# Place a dynamic ROM component.\n", + "rom1 = tb.modeler.schematic.create_component(\"ROM1\", \"\", \"staticrom\", [40 * G, 25 * G])\n", + "\n", + "# Place two excitation sources.\n", + "source1 = tb.modeler.schematic.create_periodic_waveform_source(\n", + " None, \"SINE\", 2.5, 0.01, 0, 7.5, 0, [20 * G, 29 * G]\n", + ")\n", + "source2 = tb.modeler.schematic.create_periodic_waveform_source(\n", + " None, \"SINE\", 50, 0.02, 0, 450, 0, [20 * G, 25 * G]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4e13a7cd", + "metadata": {}, + "source": [ + "Connect components with wires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24ba9cda", + "metadata": {}, + "outputs": [], + "source": [ + "tb.modeler.schematic.create_wire([[22 * G, 29 * G], [33 * G, 29 * G]])\n", + "tb.modeler.schematic.create_wire(\n", + " [[22 * G, 25 * G], [30 * G, 25 * G], [30 * G, 28 * G], [33 * G, 28 * G]]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2aaeb73c", + "metadata": {}, + "source": [ + "Enable storage of views." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32e1f1a4", + "metadata": {}, + "outputs": [], + "source": [ + "rom1.set_property(\"store_snapshots\", 1)\n", + "rom1.set_property(\"view1_storage_period\", \"10s\")\n", + "rom1.set_property(\"view2_storage_period\", \"10s\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88d956fa", + "metadata": {}, + "outputs": [], + "source": [ + "# Zoom to fit the schematic\n", + "tb.modeler.zoom_to_fit()" + ] + }, + { + "cell_type": "markdown", + "id": "7e4bd174", + "metadata": {}, + "source": [ + "## Parametrize transient setup\n", + "\n", + "Parametrize the default transient setup by setting the end time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0be88c5", + "metadata": {}, + "outputs": [], + "source": [ + "tb.set_end_time(\"300s\")\n", + "tb.set_hmin(\"1s\")\n", + "tb.set_hmax(\"1s\")" + ] + }, + { + "cell_type": "markdown", + "id": "52b40671", + "metadata": {}, + "source": [ + "## Solve transient setup\n", + "\n", + "Solve the transient setup. Skipping this step in case the documentation is being built." + ] + }, + { + "cell_type": "markdown", + "id": "ece8e796", + "metadata": {}, + "source": [ + "> **Note:** The following code can be uncommented.\n", + "\n", + "tb.analyze_setup(\"TR\")" + ] + }, + { + "cell_type": "markdown", + "id": "fadae0ee", + "metadata": {}, + "source": [ + "## Get report data and plot using Matplotlib\n", + "\n", + "Get report data and plot it using Matplotlib. The following code gets and plots\n", + "the values for the voltage on the pulse voltage source and the values for the\n", + "output of the dynamic ROM." + ] + }, + { + "cell_type": "markdown", + "id": "5a03a71f", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "> **Note:** The following code can be uncommented, but it depends on the previous commented code.\n", + "\n", + "e_value = \"ROM1.outfield_mode_1\"\n", + "x = tb.post.get_solution_data(e_value, \"TR\", \"Time\")\n", + "x.plot()\n", + "e_value = \"ROM1.outfield_mode_2\"\n", + "x = tb.post.get_solution_data(e_value, \"TR\", \"Time\")\n", + "x.plot()\n", + "e_value = \"SINE1.VAL\"\n", + "x = tb.post.get_solution_data(e_value, \"TR\", \"Time\")\n", + "x.plot()\n", + "e_value = \"SINE2.VAL\"\n", + "x = tb.post.get_solution_data(e_value, \"TR\", \"Time\")\n", + "x.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "5ea07570", + "metadata": {}, + "source": [ + "## Close Twin Builder\n", + "\n", + "After the simulation is completed, either close Twin Builder or release it.\n", + "All methods provide for saving the project before closing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e04b330e", + "metadata": {}, + "outputs": [], + "source": [ + "# Clean up the downloaded data.\n", + "shutil.rmtree(source_data_folder)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cb106a3", + "metadata": {}, + "outputs": [], + "source": [ + "# Restore earlier desktop configuration and schematic environment.\n", + "tb._odesktop.SetDesktopConfiguration(current_desktop_config)\n", + "tb._odesktop.SetSchematicEnvironment(current_schematic_environment)" + ] + }, + { + "cell_type": "markdown", + "id": "0417263c", + "metadata": {}, + "source": [ + "## Release AEDT\n", + "\n", + "Release AEDT and close the example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bad6c0f1", + "metadata": {}, + "outputs": [], + "source": [ + "tb.save_project()\n", + "tb.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "b7b48cee", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``. If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "875c0662", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/index.rst.txt b/version/dev/_sources/examples/low_frequency/index.rst.txt new file mode 100644 index 00000000..43c6af5b --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/index.rst.txt @@ -0,0 +1,95 @@ +Low frequency +============= + +These end-to-end examples show how to use PyAEDT for low-frequency applications. + + +.. grid:: 2 + + .. grid-item-card:: General + :padding: 2 2 2 2 + :link: general/index + :link-type: doc + + .. image:: _static/general.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + General examples + + .. grid-item-card:: Motor + :padding: 2 2 2 2 + :link: motor/index + :link-type: doc + + .. image:: _static/motor_maxwell.png + :alt: PCB + :width: 250px + :height: 200px + :align: center + + Motor examples + + .. grid-item-card:: Magnetics + :padding: 2 2 2 2 + :link: magnetic/index + :link-type: doc + + .. image:: _static/magnetic.png + :alt: Filter + :width: 250px + :height: 200px + :align: center + + Magnetics examples + + .. grid-item-card:: T.E.A.M + :padding: 2 2 2 2 + :link: team_problem/index + :link-type: doc + + .. image:: _static/TEAM.png + :alt: Filter + :width: 250px + :height: 200px + :align: center + + T.E.A.M. problems set by COMPUMAG + + .. grid-item-card:: Multiphysics + :padding: 2 2 2 2 + :link: multiphysics/index + :link-type: doc + + .. image:: _static/CFD_coil.png + :alt: Stress PCB + :width: 250px + :height: 200px + :align: center + + Multiphysics examples + + .. grid-item-card:: Report + :padding: 2 2 2 2 + :link: ../aedt_general/report/index + :link-type: doc + + .. image:: ../aedt_general/_static/touchstone.png + :alt: Components + :width: 250px + :height: 200px + :align: center + + These examples use PyAEDT to show some report capabilities. + + .. toctree:: + :hidden: + + general/index + motor/index + magnetic/index + team_problem/index + multiphysics/index + ../aedt_general/report/index diff --git a/version/dev/_sources/examples/low_frequency/magnetic/choke.ipynb.txt b/version/dev/_sources/examples/low_frequency/magnetic/choke.ipynb.txt new file mode 100644 index 00000000..ab269126 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/magnetic/choke.ipynb.txt @@ -0,0 +1,525 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "458f55c0", + "metadata": {}, + "source": [ + "# Choke setup\n", + "\n", + "This example shows how to use PyAEDT to create a choke setup in Maxwell 3D.\n", + "\n", + "Keywords: **Maxwell 3D**, **choke**." + ] + }, + { + "cell_type": "markdown", + "id": "c2a0ac0f", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "440f94dd", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2cb1fab2", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "64ea283d", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "911bd677", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "09636537", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a0ed571", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "80f1da21", + "metadata": {}, + "source": [ + "## Launch Maxwell3D\n", + "\n", + "Launch Maxwell 3D 2024 R2 in graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3765035b", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"choke.aedt\")\n", + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=project_name,\n", + " solution_type=\"EddyCurrent\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4a16b174", + "metadata": {}, + "source": [ + "## Define parameters\n", + "\n", + "The dictionary values contain the different parameter values of the core and\n", + "the windings that compose the choke. You must not change the main structure of\n", + "the dictionary. The dictionary has many primary keys, including\n", + "``\"Number of Windings\"``, ``\"Layer\"``, and ``\"Layer Type\"``, that have\n", + "dictionaries as values. The keys of these dictionaries are secondary keys\n", + "of the dictionary values, such as ``\"1\"``, ``\"2\"``, ``\"3\"``, ``\"4\"``, and\n", + "``\"Simple\"``.\n", + "\n", + "You must not modify the primary or secondary keys. You can modify only their values.\n", + "You must not change the data types for these keys. For the dictionaries from\n", + "``\"Number of Windings\"`` through ``\"Wire Section\"``, values must be Boolean. Only\n", + "one value per dictionary can be ``True``. If all values are ``True``, only the first one\n", + "remains set to ``True``. If all values are ``False``, the first value is chosen as the\n", + "correct one by default. For the dictionaries from ``\"Core\"`` through ``\"Inner Winding\"``,\n", + "values must be strings, floats, or integers.\n", + "\n", + "Descriptions follow for the primary keys:\n", + "\n", + "- ``\"Number of Windings\"``: Number of windings around the core.\n", + "- ``\"Layer\"``: Number of layers of all windings.\n", + "- ``\"Layer Type\"``: Whether layers of a winding are linked to each other\n", + "- ``\"Similar Layer\"``: Whether layers of a winding have the same number of turns and\n", + "same spacing between turns.\n", + "- ``\"Mode\"``: When there are only two windows, whether they are in common or differential mode.\n", + "- ``\"Wire Section\"``: Type of wire section and number of segments.\n", + "- ``\"Core\"``: Design of the core.\n", + "- ``\"Outer Winding\"``: Design of the first layer or outer layer of a winding and the common\n", + "parameters for all layers.\n", + "- ``\"Mid Winding\"``: Turns and turns spacing (``Coil Pit``) for the second or\n", + "mid layer if it is necessary.\n", + "- ``\"Inner Winding\"``: Turns and turns spacing (``Coil Pit``) for the third or inner\n", + "layer if it is necessary.\n", + "- ``\"Occupation(%)\"``: An informative parameter that is useless to modify.\n", + "\n", + "The following parameter values work. You can modify them if you want." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25118e4d", + "metadata": {}, + "outputs": [], + "source": [ + "values = {\n", + " \"Number of Windings\": {\"1\": False, \"2\": False, \"3\": True, \"4\": False},\n", + " \"Layer\": {\"Simple\": False, \"Double\": False, \"Triple\": True},\n", + " \"Layer Type\": {\"Separate\": False, \"Linked\": True},\n", + " \"Similar Layer\": {\"Similar\": False, \"Different\": True},\n", + " \"Mode\": {\"Differential\": True, \"Common\": False},\n", + " \"Wire Section\": {\"None\": False, \"Hexagon\": False, \"Octagon\": True, \"Circle\": False},\n", + " \"Core\": {\n", + " \"Name\": \"Core\",\n", + " \"Material\": \"ferrite\",\n", + " \"Inner Radius\": 100,\n", + " \"Outer Radius\": 143,\n", + " \"Height\": 25,\n", + " \"Chamfer\": 0.8,\n", + " },\n", + " \"Outer Winding\": {\n", + " \"Name\": \"Winding\",\n", + " \"Material\": \"copper\",\n", + " \"Inner Radius\": 100,\n", + " \"Outer Radius\": 143,\n", + " \"Height\": 25,\n", + " \"Wire Diameter\": 5,\n", + " \"Turns\": 2,\n", + " \"Coil Pit(deg)\": 4,\n", + " \"Occupation(%)\": 0,\n", + " },\n", + " \"Mid Winding\": {\"Turns\": 7, \"Coil Pit(deg)\": 4, \"Occupation(%)\": 0},\n", + " \"Inner Winding\": {\"Turns\": 10, \"Coil Pit(deg)\": 4, \"Occupation(%)\": 0},\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "90d4ea62", + "metadata": {}, + "source": [ + "## Convert dictionary to JSON file\n", + "\n", + "Convert the dictionary to a JSON file. PyAEDT methods ask for the path of the\n", + "JSON file as an argument. You can convert a dictionary to a JSON file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bebc1af8", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = os.path.join(temp_folder.name, \"choke_example.json\")\n", + "\n", + "with open(json_path, \"w\") as outfile:\n", + " json.dump(values, outfile)" + ] + }, + { + "cell_type": "markdown", + "id": "cbd1c52f", + "metadata": {}, + "source": [ + "## Verify parameters of JSON file\n", + "\n", + "Verify parameters of the JSON file. The ``check_choke_values()`` method takes\n", + "the JSON file path as an argument and does the following:\n", + "\n", + "- Checks if the JSON file is correctly written (as explained earlier)\n", + "- Checks equations on windings parameters to avoid having unintended intersections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d95ea94", + "metadata": {}, + "outputs": [], + "source": [ + "dictionary_values = m3d.modeler.check_choke_values(\n", + " input_dir=json_path, create_another_file=False\n", + ")\n", + "print(dictionary_values)" + ] + }, + { + "cell_type": "markdown", + "id": "32152b85", + "metadata": {}, + "source": [ + "## Create choke\n", + "\n", + "Create the choke. The ``create_choke()`` method takes the JSON file path as an\n", + "argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "743cf975", + "metadata": {}, + "outputs": [], + "source": [ + "list_object = m3d.modeler.create_choke(input_file=json_path)\n", + "print(list_object)\n", + "core = list_object[1]\n", + "first_winding_list = list_object[2]\n", + "second_winding_list = list_object[3]\n", + "third_winding_list = list_object[4]" + ] + }, + { + "cell_type": "markdown", + "id": "c3fec069", + "metadata": {}, + "source": [ + "## Assign excitations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52a41df9", + "metadata": {}, + "outputs": [], + "source": [ + "first_winding_faces = m3d.modeler.get_object_faces(\n", + " assignment=first_winding_list[0].name\n", + ")\n", + "second_winding_faces = m3d.modeler.get_object_faces(\n", + " assignment=second_winding_list[0].name\n", + ")\n", + "third_winding_faces = m3d.modeler.get_object_faces(\n", + " assignment=third_winding_list[0].name\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[first_winding_faces[-1]],\n", + " amplitude=1000,\n", + " phase=\"0deg\",\n", + " swap_direction=False,\n", + " name=\"phase_1_in\",\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[first_winding_faces[-2]],\n", + " amplitude=1000,\n", + " phase=\"0deg\",\n", + " swap_direction=True,\n", + " name=\"phase_1_out\",\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[second_winding_faces[-1]],\n", + " amplitude=1000,\n", + " phase=\"120deg\",\n", + " swap_direction=False,\n", + " name=\"phase_2_in\",\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[second_winding_faces[-2]],\n", + " amplitude=1000,\n", + " phase=\"120deg\",\n", + " swap_direction=True,\n", + " name=\"phase_2_out\",\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[third_winding_faces[-1]],\n", + " amplitude=1000,\n", + " phase=\"240deg\",\n", + " swap_direction=False,\n", + " name=\"phase_3_in\",\n", + ")\n", + "m3d.assign_current(\n", + " assignment=[third_winding_faces[-2]],\n", + " amplitude=1000,\n", + " phase=\"240deg\",\n", + " swap_direction=True,\n", + " name=\"phase_3_out\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d044b112", + "metadata": {}, + "source": [ + "## Assign matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07770f18", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.assign_matrix(\n", + " assignment=[\"phase_1_in\", \"phase_2_in\", \"phase_3_in\"], matrix_name=\"current_matrix\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2aad88a0", + "metadata": {}, + "source": [ + "## Create mesh operation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bac52ac7", + "metadata": {}, + "outputs": [], + "source": [ + "mesh = m3d.mesh\n", + "mesh.assign_skin_depth(\n", + " assignment=[first_winding_list[0], second_winding_list[0], third_winding_list[0]],\n", + " skin_depth=0.20,\n", + " triangulation_max_length=\"10mm\",\n", + " name=\"skin_depth\",\n", + ")\n", + "mesh.assign_surface_mesh_manual(\n", + " assignment=[first_winding_list[0], second_winding_list[0], third_winding_list[0]],\n", + " surface_deviation=None,\n", + " normal_dev=\"30deg\",\n", + " name=\"surface_approx\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bba8b86e", + "metadata": {}, + "source": [ + "## Create boundaries\n", + "\n", + "Create the boundaries. A region with openings is needed to run the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f2aa22a", + "metadata": {}, + "outputs": [], + "source": [ + "region = m3d.modeler.create_air_region(\n", + " x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=0\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "888b00b4", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup with a sweep to run the simulation. Depending on your machine's\n", + "computing power, the simulation can take some time to run." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03aa98d9", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m3d.create_setup(\"MySetup\")\n", + "print(setup.props)\n", + "setup.props[\"Frequency\"] = \"100kHz\"\n", + "setup.props[\"PercentRefinement\"] = 15\n", + "setup.props[\"MaximumPasses\"] = 10\n", + "setup.props[\"HasSweepSetup\"] = True\n", + "setup.add_eddy_current_sweep(\n", + " range_type=\"LinearCount\", start=100, end=1000, count=12, units=\"kHz\", clear=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "973b178a", + "metadata": {}, + "source": [ + "## Save project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b288774", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.modeler.fit_all()\n", + "m3d.plot(\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"Image.jpg\"),\n", + " plot_air_objects=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "743cee3f", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c821c19c", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "359b479a", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5ded462", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/magnetic/index.rst.txt b/version/dev/_sources/examples/low_frequency/magnetic/index.rst.txt new file mode 100644 index 00000000..0a0f440f --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/magnetic/index.rst.txt @@ -0,0 +1,68 @@ +Magnetics +~~~~~~~~~ + +These examples use PyAEDT to show some magnetics applications. + +.. grid:: 2 + + .. grid-item-card:: Transient winding analysis + :padding: 2 2 2 2 + :link: transient_winding + :link-type: doc + + .. image:: _static/transient.png + :alt: Maxwell transient + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a project in Maxwell 2D and run a transient simulation. + + .. grid-item-card:: Choke setup + :padding: 2 2 2 2 + :link: choke + :link-type: doc + + .. image:: _static/choke.png + :alt: Maxwell choke + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a choke setup in Maxwell 3D. + + + .. grid-item-card:: Magnetomotive force + :padding: 2 2 2 2 + :link: magneto_motive_line + :link-type: doc + + .. image:: _static/magneto.png + :alt: Maxwell magneto force + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to calculate the magnetomotive force. + + + .. grid-item-card:: Lorentz actuator + :padding: 2 2 2 2 + :link: lorentz_actuator + :link-type: doc + + .. image:: _static/lorentz_actuator.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a Lorentz actuator and solve it using the Maxwell 2D transient solver. + + .. toctree:: + :hidden: + + transient_winding + choke + magneto_motive_line + lorentz_actuator diff --git a/version/dev/_sources/examples/low_frequency/magnetic/lorentz_actuator.ipynb.txt b/version/dev/_sources/examples/low_frequency/magnetic/lorentz_actuator.ipynb.txt new file mode 100644 index 00000000..e1d47fc5 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/magnetic/lorentz_actuator.ipynb.txt @@ -0,0 +1,690 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c9a8c9a5", + "metadata": {}, + "source": [ + "# Lorentz actuator\n", + "\n", + "This example uses PyAEDT to set up a Lorentz actuator\n", + "and solve it using the Maxwell 2D transient solver.\n", + "\n", + "Keywords: **Maxwell2D**, **transient**, **translational motion**, **mechanical transient**" + ] + }, + { + "cell_type": "markdown", + "id": "74a29db4", + "metadata": {}, + "source": [ + "## Perform imports and define constantss\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddf6a50d", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4ece045", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "246bb467", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1adb208e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "53a06912", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e001242", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "1017cada", + "metadata": {}, + "source": [ + "## Initialize dictionaries\n", + "\n", + "Initialize the following:\n", + "\n", + "- Electric and geometric parameters for the actuator\n", + "- Simulation specifications\n", + "- Materials for the actuator component" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aee03cc9", + "metadata": {}, + "outputs": [], + "source": [ + "dimensions = {\n", + " \"Core_outer_x\": \"100mm\",\n", + " \"Core_outer_y\": \"80mm\",\n", + " \"Core_thickness\": \"10mm\",\n", + " \"Magnet_thickness\": \"10mm\",\n", + " \"Coil_width\": \"30mm\",\n", + " \"Coil_thickness\": \"5mm\",\n", + " \"Coil_inner_diameter\": \"20mm\",\n", + " \"Coil_magnet_distance\": \"5mm\",\n", + " \"Coil_start_position\": \"3mm\",\n", + " \"Band_clearance\": \"1mm\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01189909", + "metadata": {}, + "outputs": [], + "source": [ + "coil_specifications = {\n", + " \"Winding_current\": \"5A\",\n", + " \"No_of_turns\": \"100\",\n", + " \"Coil_mass\": \"0.2kg\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0acfe33e", + "metadata": {}, + "outputs": [], + "source": [ + "simulation_specifications = {\n", + " \"Mesh_bands\": \"0.5mm\",\n", + " \"Mesh_other_objects\": \"2mm\",\n", + " \"Stop_time\": \"10ms\",\n", + " \"Time_step\": \"0.5ms\",\n", + " \"Save_fields_interval\": \"1\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f404921", + "metadata": {}, + "outputs": [], + "source": [ + "materials = {\n", + " \"Coil_material\": \"copper\",\n", + " \"Core_material\": \"steel_1008\",\n", + " \"Magnet_material\": \"NdFe30\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "16088731", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D after first setting up the project name.\n", + "The following code also creates an instance of the\n", + "``Maxwell2d`` class named ``m2d`` by providing\n", + "the project name, the design name, the solver, the version, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72d5f334", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"Lorentz_actuator.aedt\")\n", + "m2d = ansys.aedt.core.Maxwell2d(\n", + " project=project_name,\n", + " design=\"1 transient 2D\",\n", + " solution_type=\"TransientXY\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fe37b032", + "metadata": {}, + "source": [ + "## Define variables from dictionaries\n", + "\n", + "Define design variables from the created dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1cf45b78", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.variable_manager.set_variable(name=\"Dimensions\")\n", + "for k, v in dimensions.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc8e5939", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.variable_manager.set_variable(name=\"Winding data\")\n", + "for k, v in coil_specifications.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5dad3648", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.variable_manager.set_variable(name=\"Simulation data\")\n", + "for k, v in simulation_specifications.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "0826cf78", + "metadata": {}, + "source": [ + "Definem materials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2de9af91", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.variable_manager.set_variable(name=\"Material data\")\n", + "m2d.logger.clear_messages()\n", + "for i, key in enumerate(materials.keys()):\n", + " if key == \"Coil_material\":\n", + " coil_mat_index = i\n", + " elif key == \"Core_material\":\n", + " core_mat_index = i\n", + " elif key == \"Magnet_material\":\n", + " magnet_mat_index = i\n", + "material_array = []\n", + "for k, v in materials.items():\n", + " material_array.append('\"' + v + '\"')\n", + "s = \", \".join(material_array)\n", + "m2d[\"Materials\"] = \"[{}]\".format(s)" + ] + }, + { + "cell_type": "markdown", + "id": "41399c2a", + "metadata": {}, + "source": [ + "## Create geometry\n", + "\n", + "Create magnetic core, coils, and magnets. Assign materials and create a coordinate system to\n", + "define the magnet orientation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba40721d", + "metadata": {}, + "outputs": [], + "source": [ + "core_id = m2d.modeler.create_rectangle(\n", + " origin=[0, 0, 0],\n", + " sizes=[\"Core_outer_x\", \"Core_outer_y\"],\n", + " name=\"Core\",\n", + " material=\"Materials[\" + str(core_mat_index) + \"]\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8b8c655", + "metadata": {}, + "outputs": [], + "source": [ + "hole_id = m2d.modeler.create_rectangle(\n", + " origin=[\"Core_thickness\", \"Core_thickness\", 0],\n", + " sizes=[\"Core_outer_x-2*Core_thickness\", \"Core_outer_y-2*Core_thickness\"],\n", + " name=\"hole\",\n", + ")\n", + "m2d.modeler.subtract(blank_list=[core_id], tool_list=[hole_id])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d3c4ccd", + "metadata": {}, + "outputs": [], + "source": [ + "magnet_n_id = m2d.modeler.create_rectangle(\n", + " origin=[\"Core_thickness\", \"Core_outer_y-2*Core_thickness\", 0],\n", + " sizes=[\"Core_outer_x-2*Core_thickness\", \"Magnet_thickness\"],\n", + " name=\"magnet_n\",\n", + " material=\"Materials[\" + str(magnet_mat_index) + \"]\",\n", + ")\n", + "magnet_s_id = m2d.modeler.create_rectangle(\n", + " origin=[\"Core_thickness\", \"Core_thickness\", 0],\n", + " sizes=[\"Core_outer_x-2*Core_thickness\", \"Magnet_thickness\"],\n", + " name=\"magnet_s\",\n", + " material=\"Materials[\" + str(magnet_mat_index) + \"]\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b0d43c8", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.modeler.create_coordinate_system(\n", + " origin=[0, 0, 0], x_pointing=[0, 1, 0], y_pointing=[1, 0, 0], name=\"cs_x_positive\"\n", + ")\n", + "m2d.modeler.create_coordinate_system(\n", + " origin=[0, 0, 0], x_pointing=[0, -1, 0], y_pointing=[1, 0, 0], name=\"cs_x_negative\"\n", + ")\n", + "magnet_s_id.part_coordinate_system = \"cs_x_positive\"\n", + "magnet_n_id.part_coordinate_system = \"cs_x_negative\"\n", + "m2d.modeler.set_working_coordinate_system(\"Global\")" + ] + }, + { + "cell_type": "markdown", + "id": "1acf9d00", + "metadata": {}, + "source": [ + "## Assign current\n", + "\n", + "Create coil terminals with 100 turns and winding with 5A current." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4709d39", + "metadata": {}, + "outputs": [], + "source": [ + "coil_in_id = m2d.modeler.create_rectangle(\n", + " origin=[\n", + " \"Core_thickness+Coil_start_position\",\n", + " \"Core_thickness+Magnet_thickness+Coil_magnet_distance\",\n", + " 0,\n", + " ],\n", + " sizes=[\"Coil_width\", \"Coil_thickness\"],\n", + " name=\"coil_in\",\n", + " material=\"Materials[\" + str(coil_mat_index) + \"]\",\n", + ")\n", + "coil_out_id = m2d.modeler.create_rectangle(\n", + " origin=[\n", + " \"Core_thickness+Coil_start_position\",\n", + " \"Core_thickness+Magnet_thickness+Coil_magnet_distance+Coil_inner_diameter+Coil_thickness\",\n", + " 0,\n", + " ],\n", + " sizes=[\"Coil_width\", \"Coil_thickness\"],\n", + " name=\"coil_out\",\n", + " material=\"Materials[\" + str(coil_mat_index) + \"]\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55aa3c2b", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_coil(\n", + " assignment=[coil_in_id],\n", + " conductors_number=\"No_of_turns\",\n", + " name=\"coil_terminal_in\",\n", + " polarity=\"Negative\",\n", + ")\n", + "m2d.assign_coil(\n", + " assignment=[coil_out_id],\n", + " conductors_number=\"No_of_turns\",\n", + " name=\"coil_terminal_out\",\n", + " polarity=\"Positive\",\n", + ")\n", + "m2d.assign_winding(is_solid=False, current=\"Winding_current\", name=\"Winding1\")\n", + "m2d.add_winding_coils(\n", + " assignment=\"Winding1\", coils=[\"coil_terminal_in\", \"coil_terminal_out\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e2ca345c", + "metadata": {}, + "source": [ + "## Assign motion\n", + "\n", + "Create band objects. All the objects within the band move. The inner band ensures that the mesh is good,\n", + "and additionally it is required when there is more than one moving object.\n", + "Assign linear motion with mechanical transient." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "345a9674", + "metadata": {}, + "outputs": [], + "source": [ + "band_id = m2d.modeler.create_rectangle(\n", + " origin=[\n", + " \"Core_thickness + Band_clearance\",\n", + " \"Core_thickness+Magnet_thickness+Band_clearance\",\n", + " 0,\n", + " ],\n", + " sizes=[\n", + " \"Core_outer_x-2*(Core_thickness+Band_clearance)\",\n", + " \"Core_outer_y-2*(Core_thickness+Band_clearance+Magnet_thickness)\",\n", + " ],\n", + " name=\"Motion_band\",\n", + ")\n", + "inner_band_id = m2d.modeler.create_rectangle(\n", + " origin=[\n", + " \"Core_thickness+Coil_start_position-Band_clearance\",\n", + " \"Core_thickness+Magnet_thickness+Coil_magnet_distance-Band_clearance\",\n", + " 0,\n", + " ],\n", + " sizes=[\n", + " \"Coil_width + 2*Band_clearance\",\n", + " \"Coil_inner_diameter+2*(Coil_thickness+Band_clearance)\",\n", + " ],\n", + " name=\"Motion_band_inner\",\n", + ")\n", + "motion_limit = \"Core_outer_x-2*(Core_thickness+Band_clearance)-(Coil_width + 2*Band_clearance)-2*Band_clearance\"\n", + "m2d.assign_translate_motion(\n", + " assignment=\"Motion_band\",\n", + " axis=\"X\",\n", + " periodic_translate=None,\n", + " mechanical_transient=True,\n", + " mass=\"Coil_mass\",\n", + " start_position=0,\n", + " negative_limit=0,\n", + " positive_limit=motion_limit,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "04b226bb", + "metadata": {}, + "source": [ + "## Create simulation domain\n", + "\n", + "Create a region and assign zero vector potential on the region edges." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a04ea68e", + "metadata": {}, + "outputs": [], + "source": [ + "region_id = m2d.modeler.create_region(pad_percent=2)\n", + "m2d.assign_vector_potential(assignment=region_id.edges, boundary=\"VectorPotential1\")" + ] + }, + { + "cell_type": "markdown", + "id": "b146c6cf", + "metadata": {}, + "source": [ + "## Assign mesh operations\n", + "\n", + "The transient solver does not have adaptive mesh refinement, so the mesh operations must be assigned." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9bfe86d", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_length_mesh(\n", + " assignment=[band_id, inner_band_id],\n", + " maximum_length=\"Mesh_bands\",\n", + " maximum_elements=None,\n", + " name=\"Bands\",\n", + ")\n", + "m2d.mesh.assign_length_mesh(\n", + " assignment=[coil_in_id, coil_in_id, core_id, magnet_n_id, magnet_s_id, region_id],\n", + " maximum_length=\"Mesh_other_objects\",\n", + " maximum_elements=None,\n", + " name=\"Coils_core_magnets\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7ac3c956", + "metadata": {}, + "source": [ + "## Turn on eddy effects\n", + "\n", + "Assign eddy effects to the magnets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "575154e4", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.eddy_effects_on(assignment=[\"magnet_n\", \"magnet_s\"])" + ] + }, + { + "cell_type": "markdown", + "id": "c8225fb8", + "metadata": {}, + "source": [ + "## Turn on core loss\n", + "\n", + "Enable core loss for the core." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05bdeeb9", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.set_core_losses(assignment=\"Core\")" + ] + }, + { + "cell_type": "markdown", + "id": "06e98099", + "metadata": {}, + "source": [ + "## Create simulation setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "601c9d21", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m2d.create_setup(name=\"Setup1\")\n", + "setup.props[\"StopTime\"] = \"Stop_time\"\n", + "setup.props[\"TimeStep\"] = \"Time_step\"\n", + "setup.props[\"SaveFieldsType\"] = \"Every N Steps\"\n", + "setup.props[\"N Steps\"] = \"Save_fields_interval\"\n", + "setup.props[\"Steps From\"] = \"0ms\"\n", + "setup.props[\"Steps To\"] = \"Stop_time\"" + ] + }, + { + "cell_type": "markdown", + "id": "3590544e", + "metadata": {}, + "source": [ + "## Create report\n", + "\n", + "Create an XY-report with force on the coil, the position of the coil on the Y axis,\n", + "and time on the X axis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40c9294c", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.create_report(\n", + " expressions=[\"Moving1.Force_x\", \"Moving1.Position\"],\n", + " plot_name=\"Force on Coil and Position of Coil\",\n", + " primary_sweep_variable=\"Time\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7697a999", + "metadata": {}, + "source": [ + "## Analyze project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4cd25e7f", + "metadata": {}, + "outputs": [], + "source": [ + "setup.analyze(cores=NUM_CORES, use_auto_settings=False)" + ] + }, + { + "cell_type": "markdown", + "id": "db01d7bd", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d95f95e5", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "a9e82b3c", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_dir.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ae3d702", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/magnetic/magneto_motive_line.ipynb.txt b/version/dev/_sources/examples/low_frequency/magnetic/magneto_motive_line.ipynb.txt new file mode 100644 index 00000000..7391f296 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/magnetic/magneto_motive_line.ipynb.txt @@ -0,0 +1,528 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d51a3158", + "metadata": {}, + "source": [ + "# Magnetomotive force along a line\n", + "\n", + "This example shows how to use PyAEDT to calculate\n", + "the magnetomotive force along a line that changes position.\n", + "It shows how to leverage the PyAEDT advanced fields calculator\n", + "to insert a custom formula, which in this case is the integral\n", + "of the H field along a line.\n", + "The example shows two options to achieve the intent.\n", + "The first one creates many lines as to simulate a contour that changes position.\n", + "The integral of the H field is computed for each line.\n", + "The second option creates one parametric polyline and then uses a parametric sweep to change its position.\n", + "The integral of the H field is computed for each position." + ] + }, + { + "cell_type": "markdown", + "id": "660c40a8", + "metadata": {}, + "source": [ + "Keywords: **Maxwell 2D**, **magnetomotive force**." + ] + }, + { + "cell_type": "markdown", + "id": "07c9f040", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e030f47", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da71858e", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "d494bc5b", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f04004e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "106540f7", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f2dc078", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "e9f3f5b4", + "metadata": {}, + "source": [ + "## Import project\n", + "\n", + "Download the files required to run this example to the temporary working folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98f865b9", + "metadata": {}, + "outputs": [], + "source": [ + "project_path = ansys.aedt.core.downloads.download_file(\n", + " source=\"maxwell_magnetic_force\",\n", + " name=\"Maxwell_Magnetic_Force.aedt\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "25a68c54", + "metadata": {}, + "source": [ + "## Initialize and launch Maxwell 2D\n", + "\n", + "Initialize and launch Maxwell 2D, providing the version and the path of the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87d94919", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = ansys.aedt.core.Maxwell2d(\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " project=project_path,\n", + " design=\"Maxwell2DDesign1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0f581b09", + "metadata": {}, + "source": [ + "# First option" + ] + }, + { + "cell_type": "markdown", + "id": "3307e932", + "metadata": {}, + "source": [ + "## Create a polyline\n", + "\n", + "Create a polyline, specifying its ends." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "142a2657", + "metadata": {}, + "outputs": [], + "source": [ + "poly = m2d.modeler.create_polyline(points=[[10, -10, 0], [10, 10, 0]], name=\"polyline\")" + ] + }, + { + "cell_type": "markdown", + "id": "23bdd6eb", + "metadata": {}, + "source": [ + "Duplicate the polyline along a vector." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a02ccdec", + "metadata": {}, + "outputs": [], + "source": [ + "polys = [poly.name]\n", + "polys.extend(poly.duplicate_along_line(vector=[-0.5, 0, 0], clones=10))" + ] + }, + { + "cell_type": "markdown", + "id": "a595e432", + "metadata": {}, + "source": [ + "## Compute magnetomotive force along each line\n", + "\n", + "Create and add a new formula to add in the PyAEDT advanced fields calculator.\n", + "Create the fields report object and get field data.\n", + "Create a data table report for the H field along each line and export it to a .csv file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "665b4f3b", + "metadata": {}, + "outputs": [], + "source": [ + "my_expression = {\n", + " \"name\": None,\n", + " \"description\": \"Magnetomotive force along a line\",\n", + " \"design_type\": [\"Maxwell 2D\", \"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"distance\",\n", + " \"assignment\": None,\n", + " \"assignment_type\": [\"Line\"],\n", + " \"operations\": [\n", + " \"Fundamental_Quantity('H')\",\n", + " \"Operation('Tangent')\",\n", + " \"Operation('Dot')\",\n", + " \"EnterLine('assignment')\",\n", + " \"Operation('LineValue')\",\n", + " \"Operation('Integrate')\",\n", + " ],\n", + " \"report\": [\"Data Table\"],\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40bbe4a2", + "metadata": {}, + "outputs": [], + "source": [ + "quantities = []\n", + "for p in polys:\n", + " quantity = \"H_field_{}\".format(p)\n", + " quantities.append(quantity)\n", + " my_expression[\"name\"] = quantity\n", + " my_expression[\"assignment\"] = quantity\n", + " m2d.post.fields_calculator.add_expression(my_expression, p)\n", + " report = m2d.post.create_report(\n", + " expressions=quantity,\n", + " context=p,\n", + " polyline_points=1,\n", + " report_category=\"Fields\",\n", + " plot_type=\"Data Table\",\n", + " plot_name=quantity,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "f2f0646c", + "metadata": {}, + "source": [ + "# Second option" + ] + }, + { + "cell_type": "markdown", + "id": "7228a2f8", + "metadata": {}, + "source": [ + "## Create a design variable\n", + "\n", + "Parametrize the polyline x position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08db0050", + "metadata": {}, + "outputs": [], + "source": [ + "m2d[\"xl\"] = \"10mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "411d6376", + "metadata": {}, + "source": [ + "## Create polyline\n", + "\n", + "Create a parametrized polyline, specifying its ends." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8df91404", + "metadata": {}, + "outputs": [], + "source": [ + "poly = m2d.modeler.create_polyline(\n", + " points=[[\"xl\", -10, 0], [\"xl\", 10, 0]], name=\"polyline_sweep\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "620f0cf1", + "metadata": {}, + "source": [ + "## Add parametric sweep\n", + "\n", + "Add a parametric sweep where the parameter to sweep is ``xl``.\n", + "Create a linear step sweep from ``10mm`` to ``15mm`` every ``1mm`` step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52485919", + "metadata": {}, + "outputs": [], + "source": [ + "param_sweep = m2d.parametrics.add(\n", + " variable=\"xl\",\n", + " start_point=\"10mm\",\n", + " end_point=\"15mm\",\n", + " step=1,\n", + " variation_type=\"LinearStep\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9cc0f1af", + "metadata": {}, + "source": [ + "## Compute magnetomotive force along the line\n", + "\n", + "Create and add a new formula to add in the PyAEDT advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "144694b5", + "metadata": {}, + "outputs": [], + "source": [ + "quantity_sweep = \"H_field_{}\".format(poly.name)\n", + "my_expression[\"name\"] = quantity_sweep\n", + "my_expression[\"assignment\"] = poly.name\n", + "m2d.post.fields_calculator.add_expression(my_expression, poly.name)" + ] + }, + { + "cell_type": "markdown", + "id": "1997c36f", + "metadata": {}, + "source": [ + "## Add parametric sweep calculation specifying the quantity (H) and save fields." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17b27068", + "metadata": {}, + "outputs": [], + "source": [ + "param_sweep.add_calculation(calculation=quantity_sweep, report_type=\"Fields\", ranges={})\n", + "param_sweep.props[\"ProdOptiSetupDataV2\"][\"SaveFields\"] = True" + ] + }, + { + "cell_type": "markdown", + "id": "63d4c9d8", + "metadata": {}, + "source": [ + "## Create data table report\n", + "\n", + "Create a data table report to display H for each polyline position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7752c883", + "metadata": {}, + "outputs": [], + "source": [ + "report_sweep = m2d.post.create_report(\n", + " expressions=quantity_sweep,\n", + " report_category=\"Fields\",\n", + " plot_type=\"Data Table\",\n", + " plot_name=quantity_sweep,\n", + " primary_sweep_variable=\"xl\",\n", + " variations={\"xl\": \"All\"},\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fb54854e", + "metadata": {}, + "source": [ + "## Analyze parametric sweep" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3ba87437", + "metadata": {}, + "outputs": [], + "source": [ + "param_sweep.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "4dafd7e9", + "metadata": {}, + "source": [ + "## Export results\n", + "\n", + "Export results in a .csv file for the parametric sweep analysis (second option)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d832844", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.export_report_to_csv(\n", + " project_dir=temp_folder.name,\n", + " plot_name=quantity_sweep,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f01d1ebc", + "metadata": {}, + "source": [ + "Export results in a .csv file for each polyline (first option)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8f9e6d7", + "metadata": {}, + "outputs": [], + "source": [ + "[\n", + " m2d.post.export_report_to_csv(\n", + " project_dir=temp_folder.name,\n", + " plot_name=q,\n", + " )\n", + " for q in quantities\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "4a47c1ec", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e61cdb9", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "3c53ab86", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0e3ac76", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/magnetic/transient_winding.ipynb.txt b/version/dev/_sources/examples/low_frequency/magnetic/transient_winding.ipynb.txt new file mode 100644 index 00000000..e712bf09 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/magnetic/transient_winding.ipynb.txt @@ -0,0 +1,381 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9d0bc6c4", + "metadata": {}, + "source": [ + "# Transient winding analysis\n", + "\n", + "This example shows how to use PyAEDT to create a project in Maxwell 2D\n", + "and run a transient simulation. It runs only on Windows using CPython.\n", + "\n", + "The following libraries are required for the advanced postprocessing features\n", + "used in this example:\n", + "\n", + "- [Matplotlib](https://pypi.org/project/matplotlib/)\n", + "- [Numpy](https://pypi.org/project/numpy/)\n", + "- [PyVista](https://pypi.org/project/pyvista/)\n", + "\n", + "Install these libraries with this command:\n", + "\n", + "```console\n", + " pip install numpy pyvista matplotlib\n", + "```\n", + "\n", + "Keywords: **Maxwell 2D**, **transient**, **winding**." + ] + }, + { + "cell_type": "markdown", + "id": "4f2d9db7", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3fc7810", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdc90d2e", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "e866a5e3", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6450720a", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "197ca991", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c7da24d", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "90f7ec4e", + "metadata": {}, + "source": [ + "## Insert Maxwell 2D design" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1ed88e9", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"Transient.aedt\")\n", + "m2d = ansys.aedt.core.Maxwell2d(\n", + " solution_type=\"TransientXY\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + " project=project_name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d2f04e2b", + "metadata": {}, + "source": [ + "## Create rectangle and duplicate it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b421d44d", + "metadata": {}, + "outputs": [], + "source": [ + "rect1 = m2d.modeler.create_rectangle(\n", + " origin=[0, 0, 0], sizes=[10, 20], name=\"winding\", material=\"copper\"\n", + ")\n", + "duplicate = rect1.duplicate_along_line(vector=[14, 0, 0])\n", + "rect2 = m2d.modeler[duplicate[0]]" + ] + }, + { + "cell_type": "markdown", + "id": "2e6304c5", + "metadata": {}, + "source": [ + "## Create air region\n", + "\n", + "Create an air region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc4e746c", + "metadata": {}, + "outputs": [], + "source": [ + "region = m2d.modeler.create_region([100, 100, 100, 100])" + ] + }, + { + "cell_type": "markdown", + "id": "166ba0dd", + "metadata": {}, + "source": [ + "## Assign windings and balloon\n", + "\n", + "Assigns windings to the sheets and a balloon to the air region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21ed3763", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_winding(\n", + " assignment=[rect1.name, rect2.name], current=\"1*sin(2*pi*50*Time)\", name=\"PHA\"\n", + ")\n", + "m2d.assign_balloon(assignment=region.edges)" + ] + }, + { + "cell_type": "markdown", + "id": "17cfdbbe", + "metadata": {}, + "source": [ + "## Create transient setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "491fa193", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m2d.create_setup()\n", + "setup.props[\"StopTime\"] = \"0.02s\"\n", + "setup.props[\"TimeStep\"] = \"0.0002s\"\n", + "setup.props[\"SaveFieldsType\"] = \"Every N Steps\"\n", + "setup.props[\"N Steps\"] = \"1\"\n", + "setup.props[\"Steps From\"] = \"0s\"\n", + "setup.props[\"Steps To\"] = \"0.002s\"" + ] + }, + { + "cell_type": "markdown", + "id": "92deffea", + "metadata": {}, + "source": [ + "## Create rectangular plot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51c7bae7", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.create_report(\n", + " expressions=\"InputCurrent(PHA)\",\n", + " domain=\"Sweep\",\n", + " primary_sweep_variable=\"Time\",\n", + " plot_name=\"Winding Plot 1\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5c6f21c8", + "metadata": {}, + "source": [ + "## Solve model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca3aa2b8", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.analyze(cores=NUM_CORES, use_auto_settings=False)" + ] + }, + { + "cell_type": "markdown", + "id": "220a71cc", + "metadata": {}, + "source": [ + "## Create output and plot using PyVista" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13cc8483", + "metadata": {}, + "outputs": [], + "source": [ + "cutlist = [\"Global:XY\"]\n", + "face_lists = rect1.faces\n", + "face_lists += rect2.faces\n", + "timesteps = [str(i * 2e-4) + \"s\" for i in range(11)]\n", + "id_list = [f.id for f in face_lists]\n", + "\n", + "gif = m2d.post.plot_animated_field(\n", + " quantity=\"Mag_B\",\n", + " assignment=id_list,\n", + " plot_type=\"Surface\",\n", + " intrinsics={\"Time\": \"0s\"},\n", + " variation_variable=\"Time\",\n", + " variations=timesteps,\n", + " show=False,\n", + " export_gif=False,\n", + ")\n", + "gif.isometric_view = False\n", + "gif.camera_position = [15, 15, 80]\n", + "gif.focal_point = [15, 15, 0]\n", + "gif.roll_angle = 0\n", + "gif.elevation_angle = 0\n", + "gif.azimuth_angle = 0\n", + "\n", + "# Set off_screen to False to visualize the animation.\n", + "# gif.off_screen = False\n", + "gif.animate()" + ] + }, + { + "cell_type": "markdown", + "id": "9015c120", + "metadata": {}, + "source": [ + "## Generate plot outside of AEDT\n", + "\n", + "Generate the same plot outside AEDT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b4535c8", + "metadata": {}, + "outputs": [], + "source": [ + "solutions = m2d.post.get_solution_data(\n", + " expressions=\"InputCurrent(PHA)\", primary_sweep_variable=\"Time\"\n", + ")\n", + "solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "8d883d4a", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8481bb56", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "695ae33c", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61b8cb97", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/index.rst.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/index.rst.txt new file mode 100644 index 00000000..8b6230f3 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/index.rst.txt @@ -0,0 +1,97 @@ +AEDT Motor +~~~~~~~~~~ + +These examples use PyAEDT to show some motor applications in AEDT. + +.. grid:: 2 + + .. grid-item-card:: PM synchronous motor transient analysis + :padding: 2 2 2 2 + :link: pm_synchronous + :link-type: doc + + .. image:: _static/pm_synchronous.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D transient analysis for an interior permanent magnet (PM) electric motor. + + .. grid-item-card:: Magnet segmentation + :padding: 2 2 2 2 + :link: magnet_segmentation + :link-type: doc + + .. image:: _static/magnet_segmentation.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to segment magnets of an electric motor. The method is valid and usable for any object you would like to segment. + + .. grid-item-card:: IPM motor design optimization + :padding: 2 2 2 2 + :link: ipm_optimization + :link-type: doc + + .. image:: _static/ipm_optimization.png + :alt: IPM Motor + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to find the best machine 2D geometry to achieve high torque and low losses with an optimetrics analysis. + + .. grid-item-card:: Transformer + :padding: 2 2 2 2 + :link: transformer + :link-type: doc + + .. image:: _static/transformer.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to set core loss given a set of power-volume [kw/m^3] curves at different frequencies. + + + .. grid-item-card:: Transformer leakage inductance calculation + :padding: 2 2 2 2 + :link: transformer_inductance + :link-type: doc + + .. image:: _static/transformer2.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example shows how to use PyAEDT to create a Maxwell 2D magnetostatic analysis to calculate transformer leakage inductance and reactance. + + + .. grid-item-card:: Motor creation and export + :padding: 2 2 2 2 + :link: rmxpert + :link-type: doc + + .. image:: _static/rmxpert.png + :alt: Maxwell general + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to create a RMxprt project and export it to Maxwell 2D. + + + .. toctree:: + :hidden: + + pm_synchronous + magnet_segmentation + ipm_optimization + transformer + transformer_inductance + rmxpert diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/ipm_optimization.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/ipm_optimization.ipynb.txt new file mode 100644 index 00000000..68b00a9a --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/ipm_optimization.ipynb.txt @@ -0,0 +1,435 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "365375f9", + "metadata": {}, + "source": [ + "# IPM geometry optimization\n", + "\n", + "This example shows how to use PyAEDT to find the best machine 2D geometry\n", + "to achieve high torque and low losses.\n", + "The example shows how to setup an optimetrics analysis to sweep geometries\n", + "for a single value of stator current angle.\n", + "The torque and losses results are then exported in a .csv file.\n", + "\n", + "Keywords: **Maxwell 2D**, **transient**, **motor**, **optimization**." + ] + }, + { + "cell_type": "markdown", + "id": "91083e13", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2bbc89c3", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80844446", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "a15f447c", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "282c9a02", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "f840178f", + "metadata": {}, + "source": [ + "## Create temporary directory and download files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d5513e0", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "4372a5a2", + "metadata": {}, + "source": [ + "## Download AEDT file example\n", + "\n", + "Set the local temporary folder to export the AEDT file to." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8eea0eb9", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_file = ansys.aedt.core.downloads.download_file(\n", + " source=\"maxwell_motor_optimization\",\n", + " name=\"IPM_optimization.aedt\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "079a390c", + "metadata": {}, + "source": [ + "## Launch Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D after first setting up the project, the version and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2039871f", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = ansys.aedt.core.Maxwell2d(\n", + " project=aedt_file,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d9efdf74", + "metadata": {}, + "source": [ + "## Add parametric setup\n", + "\n", + "Add a parametric setup made up of geometry variable sweep definitions and single value for the stator current angle.\n", + "Note: Step variations have been minimized to reduce the analysis time. If needed they can be increased by changing\n", + "the ``step`` argument." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7efd8607", + "metadata": {}, + "outputs": [], + "source": [ + "param_sweep = m2d.parametrics.add(\n", + " variable=\"bridge\",\n", + " start_point=\"0.5mm\",\n", + " end_point=\"1mm\",\n", + " step=\"0.5mm\",\n", + " variation_type=\"LinearStep\",\n", + ")\n", + "param_sweep.add_variation(\n", + " sweep_variable=\"din\",\n", + " start_point=70,\n", + " end_point=80,\n", + " step=10,\n", + " units=\"mm\",\n", + " variation_type=\"LinearStep\",\n", + ")\n", + "param_sweep.add_variation(\n", + " sweep_variable=\"phase_advance\",\n", + " start_point=0,\n", + " end_point=45,\n", + " step=45,\n", + " units=\"deg\",\n", + " variation_type=\"LinearStep\",\n", + ")\n", + "param_sweep.add_variation(\n", + " sweep_variable=\"Ipeak\", start_point=200, units=\"A\", variation_type=\"SingleValue\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "38550bf8", + "metadata": {}, + "source": [ + "## Analyze parametric sweep" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38eab320", + "metadata": {}, + "outputs": [], + "source": [ + "param_sweep.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "45e5228a", + "metadata": {}, + "source": [ + "## Post-processing\n", + "\n", + "Create reports to get torque and loss results for all variations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e699f1c6", + "metadata": {}, + "outputs": [], + "source": [ + "report_torque = m2d.post.create_report(\n", + " expressions=\"Moving1.Torque\",\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " plot_type=\"Rectangular Plot\",\n", + " plot_name=\"TorqueAllVariations\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1f69b46", + "metadata": {}, + "outputs": [], + "source": [ + "report_solid_loss = m2d.post.create_report(\n", + " expressions=\"SolidLoss\",\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " plot_type=\"Rectangular Plot\",\n", + " plot_name=\"SolidLossAllVariations\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bead52b", + "metadata": {}, + "outputs": [], + "source": [ + "report_core_loss = m2d.post.create_report(\n", + " expressions=\"CoreLoss\",\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " plot_type=\"Rectangular Plot\",\n", + " plot_name=\"CoreLossAllVariations\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "069a4028", + "metadata": {}, + "source": [ + "Get torque and loss solution data for all available variations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02d6d88a", + "metadata": {}, + "outputs": [], + "source": [ + "torque_data = m2d.post.get_solution_data(\n", + " expressions=[\"Moving1.Torque\"],\n", + " setup_sweep_name=m2d.nominal_sweep,\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " report_category=\"Standard\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00565dd2", + "metadata": {}, + "outputs": [], + "source": [ + "solid_loss_data = m2d.post.get_solution_data(\n", + " expressions=[\"CoreLoss\"],\n", + " setup_sweep_name=m2d.nominal_sweep,\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " report_category=\"Standard\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78f74057", + "metadata": {}, + "outputs": [], + "source": [ + "core_loss_data = m2d.post.get_solution_data(\n", + " expressions=[\"SolidLoss\"],\n", + " setup_sweep_name=m2d.nominal_sweep,\n", + " domain=\"Sweep\",\n", + " variations={\"bridge\": \"All\", \"din\": \"All\", \"Ipeak\": \"All\"},\n", + " primary_sweep_variable=\"Time\",\n", + " report_category=\"Standard\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "48ad0469", + "metadata": {}, + "source": [ + "Calculate torque and loss average values for each variation and write data in a .csv file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "804d5703", + "metadata": {}, + "outputs": [], + "source": [ + "csv_data = []\n", + "for var in core_loss_data.variations:\n", + " torque_data.active_variation = var\n", + " core_loss_data.active_variation = var\n", + " solid_loss_data.active_variation = var\n", + "\n", + " torque_values = torque_data.data_magnitude()\n", + " core_loss_values = core_loss_data.data_magnitude()\n", + " solid_loss_values = solid_loss_data.data_magnitude()\n", + "\n", + " torque_data_average = sum(torque_values) / len(torque_values)\n", + " core_loss_average = sum(core_loss_values) / len(core_loss_values)\n", + " solid_loss_average = sum(solid_loss_values) / len(solid_loss_values)\n", + "\n", + " csv_data.append(\n", + " {\n", + " \"active_variation\": str(torque_data.active_variation),\n", + " \"average_torque\": str(torque_data_average),\n", + " \"average_core_loss\": str(core_loss_average),\n", + " \"average_solid_loss\": str(solid_loss_average),\n", + " }\n", + " )\n", + "\n", + " with open(\n", + " os.path.join(temp_folder.name, \"motor_optimization.csv\"), \"w\", newline=\"\"\n", + " ) as csvfile:\n", + " fields = [\n", + " \"active_variation\",\n", + " \"average_torque\",\n", + " \"average_core_loss\",\n", + " \"average_solid_loss\",\n", + " ]\n", + " writer = csv.DictWriter(csvfile, fieldnames=fields)\n", + " writer.writeheader()\n", + " writer.writerows(csv_data)" + ] + }, + { + "cell_type": "markdown", + "id": "4394e0ec", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4bc083f", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "2e8d9f2e", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84dd1c3c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/magnet_segmentation.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/magnet_segmentation.ipynb.txt new file mode 100644 index 00000000..fa463cca --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/magnet_segmentation.ipynb.txt @@ -0,0 +1,306 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "984ca037", + "metadata": {}, + "source": [ + "# Magnet segmentation" + ] + }, + { + "cell_type": "markdown", + "id": "4abe2976", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to segment magnets of an electric motor.\n", + "The method is valid and usable for any object you would like to segment.\n", + "\n", + "Keywords: **Maxwell 3D**, **Magnet segmentation**." + ] + }, + { + "cell_type": "markdown", + "id": "10ba898d", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3fbd33ef", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd727ff2", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "44ef196d", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e58c82b0", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "e31bbab8", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28a79f3c", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "61d5a257", + "metadata": {}, + "source": [ + "## Download AEDT file example\n", + "\n", + "Set the local temporary folder to export the AEDT file to." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4fcb900", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_file = ansys.aedt.core.downloads.download_file(\n", + " source=\"object_segmentation\",\n", + " name=\"Motor3D_obj_segments.aedt\",\n", + " destination=temp_folder.name,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "55378cb5", + "metadata": {}, + "source": [ + "## Launch Maxwell 3D\n", + "\n", + "Launch Maxwell 3D, providing the version, rgw path to the project, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32a83288", + "metadata": {}, + "outputs": [], + "source": [ + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=aedt_file,\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cd63c7e2", + "metadata": {}, + "source": [ + "## Segment first magnet by specifying number of segments\n", + "\n", + "Select the first magnet to segment by specifying the number of segments.\n", + "The method accepts as input the list of magnets names to segment,\n", + "magnet IDs, or the magnet :class:`ansys.aedt.core.modeler.cad.object3d.Object3d` object.\n", + "When ``apply_mesh_sheets`` is enabled, the mesh sheets are also\n", + "applied in the geometry.\n", + "In the following code, the name of the magnet is also given as an input." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57a1c6de", + "metadata": {}, + "outputs": [], + "source": [ + "segments_number = 2\n", + "object_name = \"PM_I1\"\n", + "sheets_1 = m3d.modeler.objects_segmentation(\n", + " object_name,\n", + " segments=segments_number,\n", + " apply_mesh_sheets=True,\n", + " mesh_sheets=3,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "699488d6", + "metadata": {}, + "source": [ + "## Segment second magnet by specifying number of segments\n", + "\n", + "Select the second magnet to segment by specifying the number of segments.\n", + "The following code gives the ID of the magnet as an input." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a763cf68", + "metadata": {}, + "outputs": [], + "source": [ + "segments_number = 2\n", + "object_name = \"PM_I1_1\"\n", + "magnet_id = [obj.id for obj in m3d.modeler.object_list if obj.name == object_name][0]\n", + "sheets_2 = m3d.modeler.objects_segmentation(\n", + " magnet_id, segments=segments_number, apply_mesh_sheets=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2746d912", + "metadata": {}, + "source": [ + "## Segment third magnet by specifying segmentation thickness\n", + "\n", + "Select the third magnet to segment by specifying the segmentation thickness.\n", + "The following code gives the magnet object type `ansys.aedt.core.modeler.cad.object3d.Object3d`\n", + "as an input." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6eb1262", + "metadata": {}, + "outputs": [], + "source": [ + "segmentation_thickness = 1\n", + "object_name = \"PM_O1\"\n", + "magnet = [obj for obj in m3d.modeler.object_list if obj.name == object_name][0]\n", + "sheets_3 = m3d.modeler.objects_segmentation(\n", + " magnet, segmentation_thickness=segmentation_thickness, apply_mesh_sheets=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "bc4cc675", + "metadata": {}, + "source": [ + "## Segment fourth magnet by specifying number of segments\n", + "\n", + "Select the fourth magnet to segment by specifying the number of segments.\n", + "The following code gives the name of the magnet as input and disables the mesh sheets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ded3966", + "metadata": {}, + "outputs": [], + "source": [ + "object_name = \"PM_O1_1\"\n", + "segments_number = 2\n", + "sheets_4 = m3d.modeler.objects_segmentation(object_name, segments=segments_number)" + ] + }, + { + "cell_type": "markdown", + "id": "4bed7163", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a8cd6d6", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "44e68dc4", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ced6c6ed", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/pm_synchronous.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/pm_synchronous.ipynb.txt new file mode 100644 index 00000000..dd5aed59 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/pm_synchronous.ipynb.txt @@ -0,0 +1,1704 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2ced4995", + "metadata": {}, + "source": [ + "# PM synchronous motor transient analysis\n", + "\n", + "This example shows how to use PyAEDT to create a Maxwell 2D transient analysis for\n", + "an interior permanent magnet (PM) electric motor.\n", + "\n", + "Keywords: **Maxwell 2D**, **transient**, **motor**." + ] + }, + { + "cell_type": "markdown", + "id": "aab833c7", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0ba366d", + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import os\n", + "import tempfile\n", + "import time\n", + "from operator import attrgetter" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "088dacc0", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "ddbd3e8e", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01ff44c9", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "40fdebf2", + "metadata": {}, + "source": [ + "## Create temporary directory and download files\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba7fc971", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "b690616d", + "metadata": {}, + "source": [ + "## Initialize dictionaries\n", + "\n", + "Dictionaries contain all the definitions for the design variables and output variables." + ] + }, + { + "cell_type": "markdown", + "id": "ce47b7fa", + "metadata": {}, + "source": [ + "## Initialize definitions for th stator, rotor, and shaft\n", + "\n", + "Initialize geometry parameter definitions for the stator, rotor, and shaft.\n", + "The naming refers to RMxprt primitives." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5fa0c38", + "metadata": {}, + "outputs": [], + "source": [ + "geom_params = {\n", + " \"DiaGap\": \"132mm\",\n", + " \"DiaStatorYoke\": \"198mm\",\n", + " \"DiaStatorInner\": \"132mm\",\n", + " \"DiaRotorLam\": \"130mm\",\n", + " \"DiaShaft\": \"44.45mm\",\n", + " \"DiaOuter\": \"198mm\",\n", + " \"Airgap\": \"1mm\",\n", + " \"SlotNumber\": \"48\",\n", + " \"SlotType\": \"3\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "0ba39672", + "metadata": {}, + "source": [ + "## Initialize definitions for stator windings\n", + "\n", + "Initialize geometry parameter definitions for the stator windings. The naming\n", + "refers to RMxprt primitives." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a70a3464", + "metadata": {}, + "outputs": [], + "source": [ + "wind_params = {\n", + " \"Layers\": \"1\",\n", + " \"ParallelPaths\": \"2\",\n", + " \"R_Phase\": \"7.5mOhm\",\n", + " \"WdgExt_F\": \"5mm\",\n", + " \"SpanExt\": \"30mm\",\n", + " \"SegAngle\": \"0.25\",\n", + " \"CoilPitch\": \"5\", # coil pitch in slots\n", + " \"Coil_SetBack\": \"3.605732823mm\",\n", + " \"SlotWidth\": \"2.814mm\", # RMxprt Bs0\n", + " \"Coil_Edge_Short\": \"3.769235435mm\",\n", + " \"Coil_Edge_Long\": \"15.37828521mm\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "35eb64e8", + "metadata": {}, + "source": [ + "## Initialize definitions for model setup\n", + "\n", + "Initialize geometry parameter definitions for the model setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "790c7d98", + "metadata": {}, + "outputs": [], + "source": [ + "mod_params = {\n", + " \"NumPoles\": \"8\",\n", + " \"Model_Length\": \"80mm\",\n", + " \"SymmetryFactor\": \"8\",\n", + " \"Magnetic_Axial_Length\": \"150mm\",\n", + " \"Stator_Lam_Length\": \"0mm\",\n", + " \"StatorSkewAngle\": \"0deg\",\n", + " \"NumTorquePointsPerCycle\": \"30\",\n", + " \"mapping_angle\": \"0.125*4deg\",\n", + " \"num_m\": \"16\",\n", + " \"Section_Angle\": \"360deg/SymmetryFactor\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "c4b872f3", + "metadata": {}, + "source": [ + "## Initialize definitions for operational machine\n", + "\n", + "Initialize geometry parameter definitions for the operational machine. This\n", + "identifies the operating point for the transient setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08aeca0a", + "metadata": {}, + "outputs": [], + "source": [ + "oper_params = {\n", + " \"InitialPositionMD\": \"180deg/4\",\n", + " \"IPeak\": \"480A\",\n", + " \"MachineRPM\": \"3000rpm\",\n", + " \"ElectricFrequency\": \"MachineRPM/60rpm*NumPoles/2*1Hz\",\n", + " \"ElectricPeriod\": \"1/ElectricFrequency\",\n", + " \"BandTicksinModel\": \"360deg/NumPoles/mapping_angle\",\n", + " \"TimeStep\": \"ElectricPeriod/(2*BandTicksinModel)\",\n", + " \"StopTime\": \"ElectricPeriod\",\n", + " \"Theta_i\": \"135deg\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "1b4cd058", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 2D\n", + "\n", + "Launch AEDT and Maxwell 2D after first setting up the project and design names,\n", + "the solver, and the version. The following code also creates an instance of the\n", + "``Maxwell2d`` class named ``m2d``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7310e644", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"PM_Motor.aedt\")\n", + "m2d = ansys.aedt.core.Maxwell2d(\n", + " project=project_name,\n", + " version=AEDT_VERSION,\n", + " design=\"Sinusoidal\",\n", + " solution_type=\"TransientXY\",\n", + " new_desktop=True,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fb4b6f5b", + "metadata": {}, + "source": [ + "## Define modeler units" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "677e1a20", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "ae9cecb9", + "metadata": {}, + "source": [ + "## Define variables from dictionaries\n", + "\n", + "Define design variables from the created dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d58a6a4b", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in geom_params.items():\n", + " m2d[k] = v\n", + "for k, v in wind_params.items():\n", + " m2d[k] = v\n", + "for k, v in mod_params.items():\n", + " m2d[k] = v\n", + "for k, v in oper_params.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "396e59e0", + "metadata": {}, + "source": [ + "## Define path for non-linear material properties\n", + "\n", + "Define the path for non-linear material properties.\n", + "Materials are stored in text files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b2d49ea", + "metadata": {}, + "outputs": [], + "source": [ + "filename_lam, filename_PM = ansys.aedt.core.downloads.download_leaf(\n", + " destination=temp_folder.name\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "262f1816", + "metadata": {}, + "source": [ + "## Create first material\n", + "\n", + "Create the material ``\"Copper (Annealed)_65C\"``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8dfad61", + "metadata": {}, + "outputs": [], + "source": [ + "mat_coils = m2d.materials.add_material(\"Copper (Annealed)_65C\")\n", + "mat_coils.update()\n", + "mat_coils.conductivity = \"49288048.9198\"\n", + "mat_coils.permeability = \"1\"" + ] + }, + { + "cell_type": "markdown", + "id": "1e8d35e2", + "metadata": {}, + "source": [ + "## Create second material\n", + "\n", + "Create the material ``\"Arnold_Magnetics_N30UH_80C\"``.\n", + "The BH curve is read from a tabbed CSV file. A list named ``BH_List_PM``\n", + "is created. This list is passed to the ``mat_PM.permeability.value``\n", + "variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43b3f708", + "metadata": {}, + "outputs": [], + "source": [ + "mat_PM = m2d.materials.add_material(name=\"Arnold_Magnetics_N30UH_80C_new\")\n", + "mat_PM.update()\n", + "mat_PM.conductivity = \"555555.5556\"\n", + "mat_PM.set_magnetic_coercivity(value=-800146.66287534, x=1, y=0, z=0)\n", + "mat_PM.mass_density = \"7500\"\n", + "BH_List_PM = []\n", + "with open(filename_PM) as f:\n", + " reader = csv.reader(f, delimiter=\"\\t\")\n", + " next(reader)\n", + " for row in reader:\n", + " BH_List_PM.append([float(row[0]), float(row[1])])\n", + "mat_PM.permeability.value = BH_List_PM" + ] + }, + { + "cell_type": "markdown", + "id": "b1cfa213", + "metadata": {}, + "source": [ + "## Create third material\n", + "\n", + "Create the laminated material ``30DH_20C_smooth``.\n", + "This material has a BH curve and a core loss model,\n", + "which is set to electrical steel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6879ee7d", + "metadata": {}, + "outputs": [], + "source": [ + "mat_lam = m2d.materials.add_material(\"30DH_20C_smooth\")\n", + "mat_lam.update()\n", + "mat_lam.conductivity = \"1694915.25424\"\n", + "kh = 71.7180985413\n", + "kc = 0.25092214579\n", + "ke = 12.1625774023\n", + "kdc = 0.001\n", + "eq_depth = 0.001\n", + "mat_lam.set_electrical_steel_coreloss(kh, kc, ke, kdc, eq_depth)\n", + "mat_lam.mass_density = \"7650\"\n", + "BH_List_lam = []\n", + "with open(filename_lam) as f:\n", + " reader = csv.reader(f, delimiter=\"\\t\")\n", + " next(reader)\n", + " for row in reader:\n", + " BH_List_lam.append([float(row[0]), float(row[1])])\n", + "mat_lam.permeability.value = BH_List_lam" + ] + }, + { + "cell_type": "markdown", + "id": "81b58021", + "metadata": {}, + "source": [ + "## Create geometry for stator\n", + "\n", + "Create the geometry for the stator. It is created via\n", + "the RMxprt user-defined primitive (UDP). A list of lists is\n", + "created with the proper UDP parameters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9811249a", + "metadata": {}, + "outputs": [], + "source": [ + "udp_par_list_stator = [\n", + " [\"DiaGap\", \"DiaGap\"],\n", + " [\"DiaYoke\", \"DiaStatorYoke\"],\n", + " [\"Length\", \"Stator_Lam_Length\"],\n", + " [\"Skew\", \"StatorSkewAngle\"],\n", + " [\"Slots\", \"SlotNumber\"],\n", + " [\"SlotType\", \"SlotType\"],\n", + " [\"Hs0\", \"1.2mm\"],\n", + " [\"Hs01\", \"0mm\"],\n", + " [\"Hs1\", \"0.4834227384999mm\"],\n", + " [\"Hs2\", \"17.287669825502mm\"],\n", + " [\"Bs0\", \"2.814mm\"],\n", + " [\"Bs1\", \"4.71154109036mm\"],\n", + " [\"Bs2\", \"6.9777285790998mm\"],\n", + " [\"Rs\", \"2mm\"],\n", + " [\"FilletType\", \"1\"],\n", + " [\"HalfSlot\", \"0\"],\n", + " [\"VentHoles\", \"0\"],\n", + " [\"HoleDiaIn\", \"0mm\"],\n", + " [\"HoleDiaOut\", \"0mm\"],\n", + " [\"HoleLocIn\", \"0mm\"],\n", + " [\"HoleLocOut\", \"0mm\"],\n", + " [\"VentDucts\", \"0\"],\n", + " [\"DuctWidth\", \"0mm\"],\n", + " [\"DuctPitch\", \"0mm\"],\n", + " [\"SegAngle\", \"0deg\"],\n", + " [\"LenRegion\", \"Model_Length\"],\n", + " [\"InfoCore\", \"0\"],\n", + "]\n", + "\n", + "stator_id = m2d.modeler.create_udp(\n", + " dll=\"RMxprt/VentSlotCore.dll\",\n", + " parameters=udp_par_list_stator,\n", + " library=\"syslib\",\n", + " name=\"my_stator\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "e593d2a4", + "metadata": {}, + "source": [ + "## Assign properties to stator\n", + "\n", + "Assign properties to the stator. The following code assigns\n", + "the ``material``, ``name``, ``color``, and ``solve_inside`` properties." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15f2650e", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_material(assignment=stator_id, material=\"30DH_20C_smooth\")\n", + "stator_id.name = \"Stator\"\n", + "stator_id.color = (0, 0, 255) # rgb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ba27fe95", + "metadata": {}, + "outputs": [], + "source": [ + "# to be reassigned: m2d.assign material puts False if not dielectric\n", + "stator_id.solve_inside = True" + ] + }, + { + "cell_type": "markdown", + "id": "312b2049", + "metadata": {}, + "source": [ + "## Create outer and inner PMs\n", + "\n", + "Create the outer and inner PMs and assign color to them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38573000", + "metadata": {}, + "outputs": [], + "source": [ + "IM1_points = [\n", + " [56.70957112, 3.104886585, 0],\n", + " [40.25081875, 16.67243502, 0],\n", + " [38.59701538, 14.66621111, 0],\n", + " [55.05576774, 1.098662669, 0],\n", + "]\n", + "OM1_points = [\n", + " [54.37758185, 22.52393189, 0],\n", + " [59.69688156, 9.68200639, 0],\n", + " [63.26490432, 11.15992981, 0],\n", + " [57.94560461, 24.00185531, 0],\n", + "]\n", + "IPM1_id = m2d.modeler.create_polyline(\n", + " points=IM1_points,\n", + " cover_surface=True,\n", + " name=\"PM_I1\",\n", + " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", + ")\n", + "IPM1_id.color = (0, 128, 64)\n", + "OPM1_id = m2d.modeler.create_polyline(\n", + " points=OM1_points,\n", + " cover_surface=True,\n", + " name=\"PM_O1\",\n", + " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", + ")\n", + "OPM1_id.color = (0, 128, 64)" + ] + }, + { + "cell_type": "markdown", + "id": "49a7ffaf", + "metadata": {}, + "source": [ + "## Create coordinate system for PMs\n", + "\n", + "Create the coordinate system for the PMs.\n", + "In Maxwell 2D, you assign magnetization via the coordinate system.\n", + "The inputs are the object name, coordinate system name, and inner or outer magnetization." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78dfdd78", + "metadata": {}, + "outputs": [], + "source": [ + "def create_cs_magnets(pm_id, cs_name, point_direction):\n", + " edges = sorted(pm_id.edges, key=attrgetter(\"length\"), reverse=True)\n", + "\n", + " if point_direction == \"outer\":\n", + " my_axis_pos = edges[0]\n", + " elif point_direction == \"inner\":\n", + " my_axis_pos = edges[1]\n", + "\n", + " m2d.modeler.create_face_coordinate_system(\n", + " face=pm_id.faces[0],\n", + " origin=pm_id.faces[0],\n", + " axis_position=my_axis_pos,\n", + " axis=\"X\",\n", + " name=cs_name,\n", + " )\n", + " pm_id.part_coordinate_system = cs_name\n", + " m2d.modeler.set_working_coordinate_system(\"Global\")" + ] + }, + { + "cell_type": "markdown", + "id": "3fbfeaff", + "metadata": {}, + "source": [ + "## Create coordinate system for PMs in face center\n", + "\n", + "Create the coordinate system for PMs in the face center." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fc4cd24", + "metadata": {}, + "outputs": [], + "source": [ + "create_cs_magnets(IPM1_id, \"CS_\" + IPM1_id.name, \"outer\")\n", + "create_cs_magnets(OPM1_id, \"CS_\" + OPM1_id.name, \"outer\")" + ] + }, + { + "cell_type": "markdown", + "id": "5598c924", + "metadata": {}, + "source": [ + "## Duplicate and mirror PMs\n", + "\n", + "Duplicate and mirror the PMs along with the local coordinate system." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2439664c", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.modeler.duplicate_and_mirror(\n", + " assignment=[IPM1_id, OPM1_id],\n", + " origin=[0, 0, 0],\n", + " vector=[\n", + " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", + " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", + " 0,\n", + " ],\n", + ")\n", + "id_PMs = m2d.modeler.get_objects_w_string(string_name=\"PM\", case_sensitive=True)" + ] + }, + { + "cell_type": "markdown", + "id": "69e2aff5", + "metadata": {}, + "source": [ + "## Create coils" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "db9279f9", + "metadata": {}, + "outputs": [], + "source": [ + "coil_id = m2d.modeler.create_rectangle(\n", + " origin=[\"DiaRotorLam/2+Airgap+Coil_SetBack\", \"-Coil_Edge_Short/2\", 0],\n", + " sizes=[\"Coil_Edge_Long\", \"Coil_Edge_Short\", 0],\n", + " name=\"Coil\",\n", + " material=\"Copper (Annealed)_65C\",\n", + ")\n", + "coil_id.color = (255, 128, 0)\n", + "m2d.modeler.rotate(assignment=coil_id, axis=\"Z\", angle=\"360deg/SlotNumber/2\")\n", + "coil_id.duplicate_around_axis(\n", + " axis=\"Z\", angle=\"360deg/SlotNumber\", clones=\"CoilPitch+1\", create_new_objects=True\n", + ")\n", + "id_coils = m2d.modeler.get_objects_w_string(string_name=\"Coil\", case_sensitive=True)" + ] + }, + { + "cell_type": "markdown", + "id": "1fa816fb", + "metadata": {}, + "source": [ + "## Create shaft and region" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b919fa61", + "metadata": {}, + "outputs": [], + "source": [ + "region_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"DiaOuter/2\",\n", + " num_sides=\"SegAngle\",\n", + " is_covered=True,\n", + " name=\"Region\",\n", + ")\n", + "shaft_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"DiaShaft/2\",\n", + " num_sides=\"SegAngle\",\n", + " is_covered=True,\n", + " name=\"Shaft\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "38cb19b6", + "metadata": {}, + "source": [ + "## Create bands\n", + "\n", + "Create the inner band, band, and outer band." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85879297", + "metadata": {}, + "outputs": [], + "source": [ + "bandIN_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"(DiaGap - (1.5 * Airgap))/2\",\n", + " num_sides=\"mapping_angle\",\n", + " is_covered=True,\n", + " name=\"Inner_Band\",\n", + ")\n", + "bandMID_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"(DiaGap - (1.0 * Airgap))/2\",\n", + " num_sides=\"mapping_angle\",\n", + " is_covered=True,\n", + " name=\"Band\",\n", + ")\n", + "bandOUT_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"(DiaGap - (0.5 * Airgap))/2\",\n", + " num_sides=\"mapping_angle\",\n", + " is_covered=True,\n", + " name=\"Outer_Band\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "977cd35a", + "metadata": {}, + "source": [ + "## Assign motion setup to object\n", + "\n", + "Assign a motion setup to a ``Band`` object named ``RotatingBand_mid``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d5e7023", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_rotate_motion(\n", + " assignment=\"Band\",\n", + " coordinate_system=\"Global\",\n", + " axis=\"Z\",\n", + " positive_movement=True,\n", + " start_position=\"InitialPositionMD\",\n", + " angular_velocity=\"MachineRPM\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a9a1976b", + "metadata": {}, + "source": [ + "## Create list of vacuum objects\n", + "\n", + "Create a list of vacuum objects and assign color." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab9f0057", + "metadata": {}, + "outputs": [], + "source": [ + "vacuum_obj_id = [\n", + " shaft_id,\n", + " region_id,\n", + " bandIN_id,\n", + " bandMID_id,\n", + " bandOUT_id,\n", + "] # put shaft first\n", + "for item in vacuum_obj_id:\n", + " item.color = (128, 255, 255)" + ] + }, + { + "cell_type": "markdown", + "id": "1306ebd6", + "metadata": {}, + "source": [ + "## Create rotor\n", + "\n", + "Create the rotor. Holes are specific to the lamination.\n", + "Allocated PMs are created." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c41bc90", + "metadata": {}, + "outputs": [], + "source": [ + "rotor_id = m2d.modeler.create_circle(\n", + " origin=[0, 0, 0],\n", + " radius=\"DiaRotorLam/2\",\n", + " num_sides=0,\n", + " name=\"Rotor\",\n", + " material=\"30DH_20C_smooth\",\n", + ")\n", + "\n", + "rotor_id.color = (0, 128, 255)\n", + "m2d.modeler.subtract(blank_list=rotor_id, tool_list=shaft_id, keep_originals=True)\n", + "void_small_1_id = m2d.modeler.create_circle(\n", + " origin=[62, 0, 0], radius=\"2.55mm\", num_sides=0, name=\"void1\", material=\"vacuum\"\n", + ")\n", + "\n", + "m2d.modeler.duplicate_around_axis(\n", + " assignment=void_small_1_id,\n", + " axis=\"Z\",\n", + " angle=\"360deg/SymmetryFactor\",\n", + " clones=2,\n", + " create_new_objects=False,\n", + ")\n", + "\n", + "void_big_1_id = m2d.modeler.create_circle(\n", + " origin=[29.5643, 12.234389332712, 0],\n", + " radius=\"9.88mm/2\",\n", + " num_sides=0,\n", + " name=\"void_big\",\n", + " material=\"vacuum\",\n", + ")\n", + "m2d.modeler.subtract(\n", + " blank_list=rotor_id,\n", + " tool_list=[void_small_1_id, void_big_1_id],\n", + " keep_originals=False,\n", + ")\n", + "\n", + "slot_IM1_points = [\n", + " [37.5302872, 15.54555396, 0],\n", + " [55.05576774, 1.098662669, 0],\n", + " [57.33637589, 1.25, 0],\n", + " [57.28982158, 2.626565019, 0],\n", + " [40.25081875, 16.67243502, 0],\n", + "]\n", + "slot_OM1_points = [\n", + " [54.37758185, 22.52393189, 0],\n", + " [59.69688156, 9.68200639, 0],\n", + " [63.53825619, 10.5, 0],\n", + " [57.94560461, 24.00185531, 0],\n", + "]\n", + "slot_IM_id = m2d.modeler.create_polyline(\n", + " points=slot_IM1_points, cover_surface=True, name=\"slot_IM1\", material=\"vacuum\"\n", + ")\n", + "slot_OM_id = m2d.modeler.create_polyline(\n", + " points=slot_OM1_points, cover_surface=True, name=\"slot_OM1\", material=\"vacuum\"\n", + ")\n", + "\n", + "m2d.modeler.duplicate_and_mirror(\n", + " assignment=[slot_IM_id, slot_OM_id],\n", + " origin=[0, 0, 0],\n", + " vector=[\n", + " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", + " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", + " 0,\n", + " ],\n", + ")\n", + "\n", + "id_holes = m2d.modeler.get_objects_w_string(string_name=\"slot_\", case_sensitive=True)\n", + "m2d.modeler.subtract(rotor_id, id_holes, keep_originals=True)" + ] + }, + { + "cell_type": "markdown", + "id": "85e1ddd3", + "metadata": {}, + "source": [ + "## Create section of machine\n", + "\n", + "Create a section of the machine. This allows you to take\n", + "advantage of symmetries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d6b2cc0", + "metadata": {}, + "outputs": [], + "source": [ + "object_list = [stator_id, rotor_id] + vacuum_obj_id\n", + "m2d.modeler.create_coordinate_system(\n", + " origin=[0, 0, 0],\n", + " reference_cs=\"Global\",\n", + " name=\"Section\",\n", + " mode=\"axis\",\n", + " x_pointing=[\"cos(360deg/SymmetryFactor)\", \"sin(360deg/SymmetryFactor)\", 0],\n", + " y_pointing=[\"-sin(360deg/SymmetryFactor)\", \"cos(360deg/SymmetryFactor)\", 0],\n", + ")\n", + "\n", + "m2d.modeler.set_working_coordinate_system(\"Section\")\n", + "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"NegativeOnly\")\n", + "m2d.modeler.set_working_coordinate_system(\"Global\")\n", + "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"PositiveOnly\")" + ] + }, + { + "cell_type": "markdown", + "id": "0fdfbff2", + "metadata": {}, + "source": [ + "## Create boundary conditions\n", + "\n", + "Create independent and dependent boundary conditions.\n", + "Edges for assignment are picked by position.\n", + "The points for edge picking are in the airgap." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26082747", + "metadata": {}, + "outputs": [], + "source": [ + "pos_1 = \"((DiaGap - (1.0 * Airgap))/4)\"\n", + "id_bc_1 = m2d.modeler.get_edgeid_from_position(\n", + " position=[pos_1, 0, 0], assignment=\"Region\"\n", + ")\n", + "id_bc_2 = m2d.modeler.get_edgeid_from_position(\n", + " position=[\n", + " pos_1 + \"*cos((360deg/SymmetryFactor))\",\n", + " pos_1 + \"*sin((360deg/SymmetryFactor))\",\n", + " 0,\n", + " ],\n", + " assignment=\"Region\",\n", + ")\n", + "m2d.assign_master_slave(\n", + " independent=id_bc_1,\n", + " dependent=id_bc_2,\n", + " reverse_master=False,\n", + " reverse_slave=True,\n", + " same_as_master=False,\n", + " boundary=\"Matching\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5bde5411", + "metadata": {}, + "source": [ + "## Assign vector potential\n", + "\n", + "Assign a vector potential of ``0`` to the second position." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "433e096c", + "metadata": {}, + "outputs": [], + "source": [ + "pos_2 = \"(DiaOuter/2)\"\n", + "id_bc_az = m2d.modeler.get_edgeid_from_position(\n", + " position=[\n", + " pos_2 + \"*cos((360deg/SymmetryFactor/2))\",\n", + " pos_2 + \"*sin((360deg/SymmetryFactor)/2)\",\n", + " 0,\n", + " ],\n", + " assignment=\"Region\",\n", + ")\n", + "m2d.assign_vector_potential(\n", + " assignment=id_bc_az, vector_value=0, boundary=\"VectorPotentialZero\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "57065835", + "metadata": {}, + "source": [ + "## Create excitations\n", + "\n", + "Create excitations, defining phase currents for the windings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32e5c2ef", + "metadata": {}, + "outputs": [], + "source": [ + "ph_a_current = \"IPeak * cos(2*pi*ElectricFrequency*time+Theta_i)\"\n", + "ph_b_current = \"IPeak * cos(2*pi * ElectricFrequency*time - 120deg+Theta_i)\"\n", + "ph_c_current = \"IPeak * cos(2*pi * ElectricFrequency*time - 240deg+Theta_i)\"" + ] + }, + { + "cell_type": "markdown", + "id": "e92e6797", + "metadata": {}, + "source": [ + "## Define windings in phase A" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39f6279d", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_coil(\n", + " assignment=[\"Coil\"],\n", + " conductors_number=6,\n", + " polarity=\"Positive\",\n", + " name=\"CT_Ph1_P2_C1_Go\",\n", + ")\n", + "m2d.assign_coil(\n", + " assignment=[\"Coil_5\"],\n", + " conductors_number=6,\n", + " polarity=\"Negative\",\n", + " name=\"CT_Ph1_P2_C1_Ret\",\n", + ")\n", + "m2d.assign_winding(\n", + " assignment=None,\n", + " winding_type=\"Current\",\n", + " is_solid=False,\n", + " current=ph_a_current,\n", + " parallel_branches=1,\n", + " name=\"Phase_A\",\n", + ")\n", + "m2d.add_winding_coils(\n", + " assignment=\"Phase_A\", coils=[\"CT_Ph1_P2_C1_Go\", \"CT_Ph1_P2_C1_Ret\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "39770f8d", + "metadata": {}, + "source": [ + "## Define windings in phase B" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e2ef5f3a", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_coil(\n", + " assignment=\"Coil_3\",\n", + " conductors_number=6,\n", + " polarity=\"Positive\",\n", + " name=\"CT_Ph3_P1_C2_Go\",\n", + ")\n", + "m2d.assign_coil(\n", + " assignment=\"Coil_4\",\n", + " conductors_number=6,\n", + " polarity=\"Positive\",\n", + " name=\"CT_Ph3_P1_C1_Go\",\n", + ")\n", + "m2d.assign_winding(\n", + " assignment=None,\n", + " winding_type=\"Current\",\n", + " is_solid=False,\n", + " current=ph_b_current,\n", + " parallel_branches=1,\n", + " name=\"Phase_B\",\n", + ")\n", + "m2d.add_winding_coils(\n", + " assignment=\"Phase_B\", coils=[\"CT_Ph3_P1_C2_Go\", \"CT_Ph3_P1_C1_Go\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a9cb6213", + "metadata": {}, + "source": [ + "## Define windings in phase C" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9e73075", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_coil(\n", + " assignment=\"Coil_1\",\n", + " conductors_number=6,\n", + " polarity=\"Negative\",\n", + " name=\"CT_Ph2_P2_C2_Ret\",\n", + ")\n", + "m2d.assign_coil(\n", + " assignment=\"Coil_2\",\n", + " conductors_number=6,\n", + " polarity=\"Negative\",\n", + " name=\"CT_Ph2_P2_C1_Ret\",\n", + ")\n", + "m2d.assign_winding(\n", + " assignment=None,\n", + " winding_type=\"Current\",\n", + " is_solid=False,\n", + " current=ph_c_current,\n", + " parallel_branches=1,\n", + " name=\"Phase_C\",\n", + ")\n", + "m2d.add_winding_coils(\n", + " assignment=\"Phase_C\", coils=[\"CT_Ph2_P2_C2_Ret\", \"CT_Ph2_P2_C1_Ret\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fccd3150", + "metadata": {}, + "source": [ + "## Assign total current on PMs\n", + "\n", + "Assign a total current of ``0`` on the PMs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4c84363", + "metadata": {}, + "outputs": [], + "source": [ + "PM_list = id_PMs\n", + "for item in PM_list:\n", + " m2d.assign_current(assignment=item, amplitude=0, solid=True, name=item + \"_I0\")" + ] + }, + { + "cell_type": "markdown", + "id": "1e1a9952", + "metadata": {}, + "source": [ + "## Create mesh operations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcb2de5e", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_length_mesh(\n", + " assignment=id_coils,\n", + " inside_selection=True,\n", + " maximum_length=3,\n", + " maximum_elements=None,\n", + " name=\"coils\",\n", + ")\n", + "m2d.mesh.assign_length_mesh(\n", + " assignment=stator_id,\n", + " inside_selection=True,\n", + " maximum_length=3,\n", + " maximum_elements=None,\n", + " name=\"stator\",\n", + ")\n", + "m2d.mesh.assign_length_mesh(\n", + " assignment=rotor_id,\n", + " inside_selection=True,\n", + " maximum_length=3,\n", + " maximum_elements=None,\n", + " name=\"rotor\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "aa5adfae", + "metadata": {}, + "source": [ + "## Turn on core loss" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c845dd0", + "metadata": {}, + "outputs": [], + "source": [ + "core_loss_list = [\"Rotor\", \"Stator\"]\n", + "m2d.set_core_losses(core_loss_list, core_loss_on_field=True)" + ] + }, + { + "cell_type": "markdown", + "id": "7f1d2630", + "metadata": {}, + "source": [ + "## Compute transient inductance" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2468213a", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.change_inductance_computation(\n", + " compute_transient_inductance=True, incremental_matrix=False\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "aecf8122", + "metadata": {}, + "source": [ + "## Set model depth" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bb1cd43", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.model_depth = \"Magnetic_Axial_Length\"" + ] + }, + { + "cell_type": "markdown", + "id": "ae7f5a81", + "metadata": {}, + "source": [ + "## Set symmetry factor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a10c7e3", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.change_symmetry_multiplier(\"SymmetryFactor\")" + ] + }, + { + "cell_type": "markdown", + "id": "5084c4ec", + "metadata": {}, + "source": [ + "## Create setup and validate" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "029a6ec6", + "metadata": {}, + "outputs": [], + "source": [ + "setup_name = \"MySetupAuto\"\n", + "setup = m2d.create_setup(name=setup_name)\n", + "setup.props[\"StopTime\"] = \"StopTime\"\n", + "setup.props[\"TimeStep\"] = \"TimeStep\"\n", + "setup.props[\"SaveFieldsType\"] = \"None\"\n", + "setup.props[\"OutputPerObjectCoreLoss\"] = True\n", + "setup.props[\"OutputPerObjectSolidLoss\"] = True\n", + "setup.props[\"OutputError\"] = True\n", + "setup.update()\n", + "m2d.validate_simple()\n", + "\n", + "model = m2d.plot(show=False)\n", + "model.plot(os.path.join(temp_folder.name, \"Image.jpg\"))" + ] + }, + { + "cell_type": "markdown", + "id": "1cd1bfdb", + "metadata": {}, + "source": [ + "## Initialize definitions for output variables\n", + "\n", + "Initialize the definitions for the output variables.\n", + "These are used later to generate reports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "384a2257", + "metadata": {}, + "outputs": [], + "source": [ + "output_vars = {\n", + " \"Current_A\": \"InputCurrent(Phase_A)\",\n", + " \"Current_B\": \"InputCurrent(Phase_B)\",\n", + " \"Current_C\": \"InputCurrent(Phase_C)\",\n", + " \"Flux_A\": \"FluxLinkage(Phase_A)\",\n", + " \"Flux_B\": \"FluxLinkage(Phase_B)\",\n", + " \"Flux_C\": \"FluxLinkage(Phase_C)\",\n", + " \"pos\": \"(Moving1.Position -InitialPositionMD) *NumPoles/2\",\n", + " \"cos0\": \"cos(pos)\",\n", + " \"cos1\": \"cos(pos-2*PI/3)\",\n", + " \"cos2\": \"cos(pos-4*PI/3)\",\n", + " \"sin0\": \"sin(pos)\",\n", + " \"sin1\": \"sin(pos-2*PI/3)\",\n", + " \"sin2\": \"sin(pos-4*PI/3)\",\n", + " \"Flux_d\": \"2/3*(Flux_A*cos0+Flux_B*cos1+Flux_C*cos2)\",\n", + " \"Flux_q\": \"-2/3*(Flux_A*sin0+Flux_B*sin1+Flux_C*sin2)\",\n", + " \"I_d\": \"2/3*(Current_A*cos0 + Current_B*cos1 + Current_C*cos2)\",\n", + " \"I_q\": \"-2/3*(Current_A*sin0 + Current_B*sin1 + Current_C*sin2)\",\n", + " \"Irms\": \"sqrt(I_d^2+I_q^2)/sqrt(2)\",\n", + " \"ArmatureOhmicLoss_DC\": \"Irms^2*R_phase\",\n", + " \"Lad\": \"L(Phase_A,Phase_A)*cos0 + L(Phase_A,Phase_B)*cos1 + L(Phase_A,Phase_C)*cos2\",\n", + " \"Laq\": \"L(Phase_A,Phase_A)*sin0 + L(Phase_A,Phase_B)*sin1 + L(Phase_A,Phase_C)*sin2\",\n", + " \"Lbd\": \"L(Phase_B,Phase_A)*cos0 + L(Phase_B,Phase_B)*cos1 + L(Phase_B,Phase_C)*cos2\",\n", + " \"Lbq\": \"L(Phase_B,Phase_A)*sin0 + L(Phase_B,Phase_B)*sin1 + L(Phase_B,Phase_C)*sin2\",\n", + " \"Lcd\": \"L(Phase_C,Phase_A)*cos0 + L(Phase_C,Phase_B)*cos1 + L(Phase_C,Phase_C)*cos2\",\n", + " \"Lcq\": \"L(Phase_C,Phase_A)*sin0 + L(Phase_C,Phase_B)*sin1 + L(Phase_C,Phase_C)*sin2\",\n", + " \"L_d\": \"(Lad*cos0 + Lbd*cos1 + Lcd*cos2) * 2/3\",\n", + " \"L_q\": \"(Laq*sin0 + Lbq*sin1 + Lcq*sin2) * 2/3\",\n", + " \"OutputPower\": \"Moving1.Speed*Moving1.Torque\",\n", + " \"Ui_A\": \"InducedVoltage(Phase_A)\",\n", + " \"Ui_B\": \"InducedVoltage(Phase_B)\",\n", + " \"Ui_C\": \"InducedVoltage(Phase_C)\",\n", + " \"Ui_d\": \"2/3*(Ui_A*cos0 + Ui_B*cos1 + Ui_C*cos2)\",\n", + " \"Ui_q\": \"-2/3*(Ui_A*sin0 + Ui_B*sin1 + Ui_C*sin2)\",\n", + " \"U_A\": \"Ui_A+R_Phase*Current_A\",\n", + " \"U_B\": \"Ui_B+R_Phase*Current_B\",\n", + " \"U_C\": \"Ui_C+R_Phase*Current_C\",\n", + " \"U_d\": \"2/3*(U_A*cos0 + U_B*cos1 + U_C*cos2)\",\n", + " \"U_q\": \"-2/3*(U_A*sin0 + U_B*sin1 + U_C*sin2)\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "3424fbc9", + "metadata": {}, + "source": [ + "## Create output variables for postprocessing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae3082fd", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in output_vars.items():\n", + " m2d.create_output_variable(k, v)" + ] + }, + { + "cell_type": "markdown", + "id": "cb8f4c52", + "metadata": {}, + "source": [ + "## Initialize definition for postprocessing plots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "457c9ef9", + "metadata": {}, + "outputs": [], + "source": [ + "post_params = {\"Moving1.Torque\": \"TorquePlots\"}" + ] + }, + { + "cell_type": "markdown", + "id": "b43c4af4", + "metadata": {}, + "source": [ + "## Initialize definition for postprocessing multiplots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79b389fd", + "metadata": {}, + "outputs": [], + "source": [ + "post_params_multiplot = { # reports\n", + " (\"U_A\", \"U_B\", \"U_C\", \"Ui_A\", \"Ui_B\", \"Ui_C\"): \"PhaseVoltages\",\n", + " (\"CoreLoss\", \"SolidLoss\", \"ArmatureOhmicLoss_DC\"): \"Losses\",\n", + " (\n", + " \"InputCurrent(Phase_A)\",\n", + " \"InputCurrent(Phase_B)\",\n", + " \"InputCurrent(Phase_C)\",\n", + " ): \"PhaseCurrents\",\n", + " (\n", + " \"FluxLinkage(Phase_A)\",\n", + " \"FluxLinkage(Phase_B)\",\n", + " \"FluxLinkage(Phase_C)\",\n", + " ): \"PhaseFluxes\",\n", + " (\"I_d\", \"I_q\"): \"Currents_dq\",\n", + " (\"Flux_d\", \"Flux_q\"): \"Fluxes_dq\",\n", + " (\"Ui_d\", \"Ui_q\"): \"InducedVoltages_dq\",\n", + " (\"U_d\", \"U_q\"): \"Voltages_dq\",\n", + " (\n", + " \"L(Phase_A,Phase_A)\",\n", + " \"L(Phase_B,Phase_B)\",\n", + " \"L(Phase_C,Phase_C)\",\n", + " \"L(Phase_A,Phase_B)\",\n", + " \"L(Phase_A,Phase_C)\",\n", + " \"L(Phase_B,Phase_C)\",\n", + " ): \"PhaseInductances\",\n", + " (\"L_d\", \"L_q\"): \"Inductances_dq\",\n", + " (\"CoreLoss\", \"CoreLoss(Stator)\", \"CoreLoss(Rotor)\"): \"CoreLosses\",\n", + " (\n", + " \"EddyCurrentLoss\",\n", + " \"EddyCurrentLoss(Stator)\",\n", + " \"EddyCurrentLoss(Rotor)\",\n", + " ): \"EddyCurrentLosses (Core)\",\n", + " (\"ExcessLoss\", \"ExcessLoss(Stator)\", \"ExcessLoss(Rotor)\"): \"ExcessLosses (Core)\",\n", + " (\n", + " \"HysteresisLoss\",\n", + " \"HysteresisLoss(Stator)\",\n", + " \"HysteresisLoss(Rotor)\",\n", + " ): \"HysteresisLosses (Core)\",\n", + " (\n", + " \"SolidLoss\",\n", + " \"SolidLoss(IPM1)\",\n", + " \"SolidLoss(IPM1_1)\",\n", + " \"SolidLoss(OPM1)\",\n", + " \"SolidLoss(OPM1_1)\",\n", + " ): \"SolidLoss\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "d864f8b9", + "metadata": {}, + "source": [ + "## Create report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e5f33d7", + "metadata": {}, + "outputs": [], + "source": [ + "for k, v in post_params.items():\n", + " m2d.post.create_report(\n", + " expressions=k,\n", + " setup_sweep_name=\"\",\n", + " domain=\"Sweep\",\n", + " variations=None,\n", + " primary_sweep_variable=\"Time\",\n", + " secondary_sweep_variable=None,\n", + " report_category=None,\n", + " plot_type=\"Rectangular Plot\",\n", + " context=None,\n", + " subdesign_id=None,\n", + " polyline_points=1001,\n", + " plot_name=v,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "23f5a674", + "metadata": {}, + "source": [ + "## Create multiplot report" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3ae5700", + "metadata": {}, + "outputs": [], + "source": [ + "# for k, v in post_params_multiplot.items():\n", + "# m2d.post.create_report(expressions=list(k), setup_sweep_name=\"\",\n", + "# domain=\"Sweep\", variations=None,\n", + "# primary_sweep_variable=\"Time\", secondary_sweep_variable=None,\n", + "# report_category=None, plot_type=\"Rectangular Plot\",\n", + "# context=None, subdesign_id=None,\n", + "# polyline_points=1001, plotname=v)" + ] + }, + { + "cell_type": "markdown", + "id": "2b506294", + "metadata": {}, + "source": [ + "## Analyze and save project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e80ee06c", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.analyze_setup(setup_name, use_auto_settings=False, cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "51af40a2", + "metadata": {}, + "source": [ + "## Create flux lines plot on region\n", + "\n", + "Create a flux lines plot on a region. The ``object_list`` is\n", + "formerly created when the section is applied." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0eafb9b4", + "metadata": {}, + "outputs": [], + "source": [ + "faces_reg = m2d.modeler.get_object_faces(object_list[1].name) # Region\n", + "plot1 = m2d.post.create_fieldplot_surface(\n", + " assignment=faces_reg,\n", + " quantity=\"Flux_Lines\",\n", + " intrinsics={\"Time\": m2d.variable_manager.variables[\"StopTime\"].evaluated_value},\n", + " plot_name=\"Flux_Lines\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ba89201d", + "metadata": {}, + "source": [ + "## Export a field plot to an image file\n", + "\n", + "Export the flux lines plot to an image file using Python PyVista." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bacff1d", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.plot_field_from_fieldplot(plot1.name, show=False)" + ] + }, + { + "cell_type": "markdown", + "id": "feaba85c", + "metadata": {}, + "source": [ + "## Get solution data\n", + "\n", + "Get a simulation result from a solved setup and cast it in a ``SolutionData`` object.\n", + "Plot the desired expression by using the Matplotlib ``plot()`` function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85c789b4", + "metadata": {}, + "outputs": [], + "source": [ + "solutions = m2d.post.get_solution_data(\n", + " expressions=\"Moving1.Torque\", primary_sweep_variable=\"Time\"\n", + ")\n", + "# solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "80ab2b21", + "metadata": {}, + "source": [ + "## Retrieve the data magnitude of an expression\n", + "\n", + "List of shaft torque points and compute average." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78f60090", + "metadata": {}, + "outputs": [], + "source": [ + "mag = solutions.data_magnitude()\n", + "avg = sum(mag) / len(mag)" + ] + }, + { + "cell_type": "markdown", + "id": "57d79678", + "metadata": {}, + "source": [ + "## Export a report to a file\n", + "\n", + "Export 2D plot data to a CSV file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00721875", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.post.export_report_to_file(\n", + " output_dir=temp_folder.name, plot_name=\"TorquePlots\", extension=\".csv\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "de42755b", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "05d2f3a4", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "e80d5cd8", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdf3173b", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/rmxpert.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/rmxpert.ipynb.txt new file mode 100644 index 00000000..48204121 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/rmxpert.ipynb.txt @@ -0,0 +1,410 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ff4d454f", + "metadata": {}, + "source": [ + "# Motor creation and export\n", + "\n", + "This example uses PyAEDT to create a RMxprt project and export it to Maxwell 2D.\n", + "It shows how to create an ASSM (Adjust-Speed Synchronous Machine) in RMxprt\n", + "and how to access rotor and stator settings.\n", + "It then exports the model to a Maxwell 2D design\n", + "and the RMxprt settings to a JSON file to be reused.\n", + "\n", + "Keywords: **RMxprt**, **Maxwell 2D**" + ] + }, + { + "cell_type": "markdown", + "id": "19b0e8cf", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae08a967", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8179d58", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "12bedb96", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a62a1fe", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "0c4f0847", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "843b2c28", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "6a6db4ec", + "metadata": {}, + "source": [ + "## Launch AEDT and RMxprt\n", + "\n", + "Launch AEDT and RMxprt after first setting up the project name.\n", + "This example uses ASSM (Adjust-Speed Synchronous Machine) as the solution type." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1d9f945", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"ASSM.aedt\")\n", + "rmxprt = ansys.aedt.core.Rmxprt(\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " close_on_exit=True,\n", + " solution_type=\"ASSM\",\n", + " project=project_name,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f42f4a31", + "metadata": {}, + "source": [ + "## Define global machine settings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdcd5eed", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.general[\"Number of Poles\"] = 4\n", + "rmxprt.general[\"Rotor Position\"] = \"Inner Rotor\"\n", + "rmxprt.general[\"Frictional Loss\"] = \"12W\"\n", + "rmxprt.general[\"Windage Loss\"] = \"0W\"\n", + "rmxprt.general[\"Reference Speed\"] = \"1500rpm\"\n", + "rmxprt.general[\"Control Type\"] = \"DC\"\n", + "rmxprt.general[\"Circuit Type\"] = \"Y3\"" + ] + }, + { + "cell_type": "markdown", + "id": "c49c7fd4", + "metadata": {}, + "source": [ + "## Define circuit settings" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4921c24", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.circuit[\"Trigger Pulse Width\"] = \"120deg\"\n", + "rmxprt.circuit[\"Transistor Drop\"] = \"2V\"\n", + "rmxprt.circuit[\"Diode Drop\"] = \"2V\"" + ] + }, + { + "cell_type": "markdown", + "id": "62a7d305", + "metadata": {}, + "source": [ + "## Define stator\n", + "\n", + "Define stator and slot and winding settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3c71158", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.stator[\"Outer Diameter\"] = \"122mm\"\n", + "rmxprt.stator[\"Inner Diameter\"] = \"75mm\"\n", + "rmxprt.stator[\"Length\"] = \"65mm\"\n", + "rmxprt.stator[\"Stacking Factor\"] = 0.95\n", + "rmxprt.stator[\"Steel Type\"] = \"steel_1008\"\n", + "rmxprt.stator[\"Number of Slots\"] = 24\n", + "rmxprt.stator[\"Slot Type\"] = 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31b1f920", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.stator.properties.children[\"Slot\"].props[\"Auto Design\"] = False\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Hs0\"] = \"0.5mm\"\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Hs1\"] = \"1.2mm\"\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Hs2\"] = \"8.2mm\"\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Bs0\"] = \"2.5mm\"\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Bs1\"] = \"5.6mm\"\n", + "rmxprt.stator.properties.children[\"Slot\"].props[\"Bs2\"] = \"7.6mm\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52051429", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.stator.properties.children[\"Winding\"].props[\"Winding Layers\"] = 2\n", + "rmxprt.stator.properties.children[\"Winding\"].props[\"Parallel Branches\"] = 1\n", + "rmxprt.stator.properties.children[\"Winding\"].props[\"Conductors per Slot\"] = 52\n", + "rmxprt.stator.properties.children[\"Winding\"].props[\"Coil Pitch\"] = 5\n", + "rmxprt.stator.properties.children[\"Winding\"].props[\"Number of Strands\"] = 1" + ] + }, + { + "cell_type": "markdown", + "id": "b9984cd1", + "metadata": {}, + "source": [ + "## Define rotor\n", + "\n", + "Define rotor and pole settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4c222c5", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.rotor[\"Outer Diameter\"] = \"74mm\"\n", + "rmxprt.rotor[\"Inner Diameter\"] = \"26mm\"\n", + "rmxprt.rotor[\"Length\"] = \"65mm\"\n", + "rmxprt.rotor[\"Stacking Factor\"] = 0.95\n", + "rmxprt.rotor[\"Steel Type\"] = \"steel_1008\"\n", + "rmxprt.rotor[\"Pole Type\"] = 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69ee4ee0", + "metadata": {}, + "outputs": [], + "source": [ + "rmxprt.rotor.properties.children[\"Pole\"].props[\"Embrace\"] = 0.7\n", + "rmxprt.rotor.properties.children[\"Pole\"].props[\"Offset\"] = \"0mm\"\n", + "rmxprt.rotor.properties.children[\"Pole\"].props[\"Magnet Type\"] = [\n", + " \"Material:=\",\n", + " \"Alnico9\",\n", + "]\n", + "rmxprt.rotor.properties.children[\"Pole\"].props[\"Magnet Thickness\"] = \"3.5mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "35021adf", + "metadata": {}, + "source": [ + "## Create setup\n", + "\n", + "Create a setup and define the main settings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e32d0f19", + "metadata": {}, + "outputs": [], + "source": [ + "setup = rmxprt.create_setup()\n", + "setup.props[\"RatedVoltage\"] = \"220V\"\n", + "setup.props[\"RatedOutputPower\"] = \"550W\"\n", + "setup.props[\"RatedSpeed\"] = \"1500rpm\"\n", + "setup.props[\"OperatingTemperature\"] = \"75cel\"" + ] + }, + { + "cell_type": "markdown", + "id": "b67065e8", + "metadata": {}, + "source": [ + "## Analyze setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9e9fff8", + "metadata": {}, + "outputs": [], + "source": [ + "setup.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "df670806", + "metadata": {}, + "source": [ + "## Export to Maxwell\n", + "\n", + "After the project is solved, you can export it to either Maxwell 2D or Maxwell 3D." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4bf8c91", + "metadata": {}, + "outputs": [], + "source": [ + "m2d = rmxprt.create_maxwell_design(setup_name=setup.name, maxwell_2d=True)\n", + "m2d.plot(\n", + " show=False,\n", + " output_file=os.path.join(temp_folder.name, \"Image.jpg\"),\n", + " plot_air_objects=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5dafb081", + "metadata": {}, + "source": [ + "## Export RMxprt settings\n", + "\n", + "Export all RMxprt settings to a JSON file to reuse it for another\n", + "project with the the import function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af108f30", + "metadata": {}, + "outputs": [], + "source": [ + "config = rmxprt.export_configuration(os.path.join(temp_folder.name, \"assm.json\"))\n", + "rmxprt2 = ansys.aedt.core.Rmxprt(\n", + " project=\"assm_test2\",\n", + " solution_type=rmxprt.solution_type,\n", + " design=\"from_configuration\",\n", + ")\n", + "rmxprt2.import_configuration(config)" + ] + }, + { + "cell_type": "markdown", + "id": "170adae0", + "metadata": {}, + "source": [ + "## Save project\n", + "\n", + "Save the project containing the Maxwell design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5074d734", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project(file_name=project_name)" + ] + }, + { + "cell_type": "markdown", + "id": "02d7702e", + "metadata": {}, + "source": [ + "## Release AEDT and clean up temporary directory\n", + "\n", + "Release AEDT and remove both the project and temporary directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1cf0b124", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.release_desktop()\n", + "time.sleep(3)\n", + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer.ipynb.txt new file mode 100644 index 00000000..3d12ba2a --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer.ipynb.txt @@ -0,0 +1,285 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "aed1ca7c", + "metadata": {}, + "source": [ + "# Transformer" + ] + }, + { + "cell_type": "markdown", + "id": "81b25f71", + "metadata": {}, + "source": [ + "This example shows how to use PyAEDT to set core loss given a set\n", + "of power-volume [kw/m^3] curves at different frequencies.\n", + "\n", + "Keywords: **Maxwell 3D**, **Transformer**." + ] + }, + { + "cell_type": "markdown", + "id": "226e0e6d", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2535fdca", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b26bd037", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Maxwell3d, downloads\n", + "from ansys.aedt.core.generic.constants import unit_converter\n", + "from ansys.aedt.core.generic.general_methods import read_csv_pandas" + ] + }, + { + "cell_type": "markdown", + "id": "bde489fc", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b37ed0e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False" + ] + }, + { + "cell_type": "markdown", + "id": "777aaa5b", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb776ca7", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "73e5c201", + "metadata": {}, + "source": [ + "## Download AEDT file example\n", + "\n", + "Download the files required to run this example to the temporary working folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0455206e", + "metadata": {}, + "outputs": [], + "source": [ + "aedt_file = downloads.download_file(\n", + " source=\"core_loss_transformer\",\n", + " name=\"Ex2-PlanarTransformer_2023R2.aedtz\",\n", + " destination=temp_folder.name,\n", + ")\n", + "freq_curve_csv_25kHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_25kHz.csv\", destination=temp_folder.name\n", + ")\n", + "freq_curve_csv_100kHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_100kHz.csv\", destination=temp_folder.name\n", + ")\n", + "freq_curve_csv_200kHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_200kHz.csv\", destination=temp_folder.name\n", + ")\n", + "freq_curve_csv_400kHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_400kHz.csv\", destination=temp_folder.name\n", + ")\n", + "freq_curve_csv_700kHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_700kHz.csv\", destination=temp_folder.name\n", + ")\n", + "freq_curve_csv_1MHz = downloads.download_file(\n", + " source=\"core_loss_transformer\", name=\"mf3_1MHz.csv\", destination=temp_folder.name\n", + ")\n", + "\n", + "data = read_csv_pandas(input_file=freq_curve_csv_25kHz)\n", + "curves_csv_25kHz = list(zip(data[data.columns[0]], data[data.columns[1]]))\n", + "data = read_csv_pandas(input_file=freq_curve_csv_100kHz)\n", + "curves_csv_100kHz = list(zip(data[data.columns[0]], data[data.columns[1]]))\n", + "data = read_csv_pandas(input_file=freq_curve_csv_200kHz)\n", + "curves_csv_200kHz = list(zip(data[data.columns[0]], data[data.columns[1]]))\n", + "data = read_csv_pandas(input_file=freq_curve_csv_400kHz)\n", + "curves_csv_400kHz = list(zip(data[data.columns[0]], data[data.columns[1]]))\n", + "data = read_csv_pandas(input_file=freq_curve_csv_700kHz)\n", + "curves_csv_700kHz = list(zip(data[data.columns[0]], data[data.columns[1]]))\n", + "data = read_csv_pandas(input_file=freq_curve_csv_1MHz)\n", + "curves_csv_1MHz = list(zip(data[data.columns[0]], data[data.columns[1]]))" + ] + }, + { + "cell_type": "markdown", + "id": "62f9773c", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 3D\n", + "\n", + "Create an instance of the ``Maxwell3d`` class named ``m3d`` by providing\n", + "the project and design names, the version, and the graphical mode." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1696bf69", + "metadata": {}, + "outputs": [], + "source": [ + "m3d = Maxwell3d(\n", + " project=aedt_file,\n", + " design=\"02_3D eddycurrent_CmXY_for_thermal\",\n", + " version=AEDT_VERSION,\n", + " new_desktop=True,\n", + " non_graphical=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "20b4f440", + "metadata": {}, + "source": [ + "## Set core loss at frequencies\n", + "\n", + "Create a new material, create a dictionary of power-volume [kw/m^3] points\n", + "for a set of frequencies retrieved from datasheet provided by a supplier,\n", + "and finally set the Power-Ferrite core loss model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62f9b5b5", + "metadata": {}, + "outputs": [], + "source": [ + "mat = m3d.materials.add_material(\"newmat\")\n", + "freq_25kHz = unit_converter(\n", + " values=25, unit_system=\"Freq\", input_units=\"kHz\", output_units=\"Hz\"\n", + ")\n", + "freq_100kHz = unit_converter(\n", + " values=100, unit_system=\"Freq\", input_units=\"kHz\", output_units=\"Hz\"\n", + ")\n", + "freq_200kHz = unit_converter(\n", + " values=200, unit_system=\"Freq\", input_units=\"kHz\", output_units=\"Hz\"\n", + ")\n", + "freq_400kHz = unit_converter(\n", + " values=400, unit_system=\"Freq\", input_units=\"kHz\", output_units=\"Hz\"\n", + ")\n", + "freq_700kHz = unit_converter(\n", + " values=700, unit_system=\"Freq\", input_units=\"kHz\", output_units=\"Hz\"\n", + ")\n", + "pv = {\n", + " freq_25kHz: curves_csv_25kHz,\n", + " freq_100kHz: curves_csv_100kHz,\n", + " freq_200kHz: curves_csv_200kHz,\n", + " freq_400kHz: curves_csv_400kHz,\n", + " freq_700kHz: curves_csv_700kHz,\n", + "}\n", + "m3d.materials[mat.name].set_coreloss_at_frequency(\n", + " points_at_frequency=pv,\n", + " coefficient_setup=\"kw_per_cubic_meter\",\n", + " core_loss_model_type=\"Power Ferrite\",\n", + ")\n", + "coefficients = m3d.materials[mat.name].get_core_loss_coefficients(\n", + " points_at_frequency=pv, coefficient_setup=\"kw_per_cubic_meter\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "14550946", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0579fdc3", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "16d54c49", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f4365b3", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer_inductance.ipynb.txt b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer_inductance.ipynb.txt new file mode 100644 index 00000000..c1fd8094 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/aedt_motor/transformer_inductance.ipynb.txt @@ -0,0 +1,522 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6996f818", + "metadata": {}, + "source": [ + "# Transformer leakage inductance calculation\n", + "\n", + "This example shows how to use PyAEDT to create a Maxwell 2D\n", + "magnetostatic analysis to calculate transformer leakage\n", + "inductance and reactance.\n", + "The analysis based on this document is from page 8 in Professor S. V.\n", + "Kulkami's paper, [Basis of Finite Element Method](https://www.ee.iitb.ac.in/~fclab/FEM/FEM1.pdf).\n", + "\n", + "Keywords: **Maxwell 2D**, **transformer**, **motor**." + ] + }, + { + "cell_type": "markdown", + "id": "566d3297", + "metadata": {}, + "source": [ + "## Perform imports and define constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de0b3f16", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3621775", + "metadata": {}, + "outputs": [], + "source": [ + "from ansys.aedt.core import Maxwell2d" + ] + }, + { + "cell_type": "markdown", + "id": "08968afb", + "metadata": {}, + "source": [ + "Define constants," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be3537ae", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "e5e59a66", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "204805cb", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "b2467fcc", + "metadata": {}, + "source": [ + "## Initialize and launch Maxwell 2D\n", + "\n", + "Initialize and launch Maxwell 2D, providing the version, the path to the project, the design\n", + "name, and the type." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7cd99ca8", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "project_name = os.path.join(temp_folder.name, \"Magnetostatic.aedt\")\n", + "m2d = Maxwell2d(\n", + " version=AEDT_VERSION,\n", + " new_desktop=False,\n", + " design=\"Transformer_leakage_inductance\",\n", + " project=project_name,\n", + " solution_type=\"MagnetostaticXY\",\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ff12b537", + "metadata": {}, + "source": [ + "## Initialize dictionaries\n", + "\n", + "Set modeler units and initialize dictionaries\n", + "that contain all the definitions for the design variables." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73d2e6c1", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.modeler.model_units = \"mm\"\n", + "\n", + "dimensions = {\n", + " \"core_width\": \"1097mm\",\n", + " \"core_height\": \"2880mm\",\n", + " \"core_opening_x1\": \"270mm\",\n", + " \"core_opening_x2\": \"557mm\",\n", + " \"core_opening_y1\": \"540mm\",\n", + " \"core_opening_y2\": \"2340mm\",\n", + " \"core_opening_width\": \"core_opening_x2-core_opening_x1\",\n", + " \"core_opening_height\": \"core_opening_y2-core_opening_y1\",\n", + " \"LV_x1\": \"293mm\",\n", + " \"LV_x2\": \"345mm\",\n", + " \"LV_width\": \"LV_x2-LV_x1\",\n", + " \"LV_mean_radius\": \"LV_x1+LV_width/2\",\n", + " \"LV_mean_turn_length\": \"pi*2*LV_mean_radius\",\n", + " \"LV_y1\": \"620mm\",\n", + " \"LV_y2\": \"2140mm\",\n", + " \"LV_height\": \"LV_y2-LV_y1\",\n", + " \"HV_x1\": \"394mm\",\n", + " \"HV_x2\": \"459mm\",\n", + " \"HV_width\": \"HV_x2-HV_x1\",\n", + " \"HV_mean_radius\": \"HV_x1+HV_width/2\",\n", + " \"HV_mean_turn_length\": \"pi*2*HV_mean_radius\",\n", + " \"HV_y1\": \"620mm\",\n", + " \"HV_y2\": \"2140mm\",\n", + " \"HV_height\": \"HV_y2-HV_y1\",\n", + " \"HV_LV_gap_radius\": \"(LV_x2 + HV_x1)/2\",\n", + " \"HV_LV_gap_length\": \"pi*2*HV_LV_gap_radius\",\n", + "}\n", + "\n", + "specifications = {\n", + " \"Amp_turns\": \"135024A\",\n", + " \"Frequency\": \"50Hz\",\n", + " \"HV_turns\": \"980\",\n", + " \"HV_current\": \"Amp_turns/HV_turns\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "49be0580", + "metadata": {}, + "source": [ + "## Define variables from dictionaries\n", + "\n", + "Define design variables from the created dictionaries." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb23d5be", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.variable_manager.set_variable(name=\"Dimensions\")\n", + "\n", + "for k, v in dimensions.items():\n", + " m2d[k] = v\n", + "\n", + "m2d.variable_manager.set_variable(name=\"Windings\")\n", + "\n", + "for k, v in specifications.items():\n", + " m2d[k] = v" + ] + }, + { + "cell_type": "markdown", + "id": "65eacb57", + "metadata": {}, + "source": [ + "## Create design geometries\n", + "\n", + "Create the transformer core, the HV and LV windings, and the region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f7d6c4f", + "metadata": {}, + "outputs": [], + "source": [ + "core = m2d.modeler.create_rectangle(\n", + " origin=[0, 0, 0],\n", + " sizes=[\"core_width\", \"core_height\", 0],\n", + " name=\"core\",\n", + " material=\"steel_1008\",\n", + ")\n", + "\n", + "core_hole = m2d.modeler.create_rectangle(\n", + " origin=[\"core_opening_x1\", \"core_opening_y1\", 0],\n", + " sizes=[\"core_opening_width\", \"core_opening_height\", 0],\n", + " name=\"core_hole\",\n", + ")\n", + "\n", + "m2d.modeler.subtract(blank_list=[core], tool_list=[core_hole], keep_originals=False)\n", + "\n", + "lv = m2d.modeler.create_rectangle(\n", + " origin=[\"LV_x1\", \"LV_y1\", 0],\n", + " sizes=[\"LV_width\", \"LV_height\", 0],\n", + " name=\"LV\",\n", + " material=\"copper\",\n", + ")\n", + "\n", + "hv = m2d.modeler.create_rectangle(\n", + " origin=[\"HV_x1\", \"HV_y1\", 0],\n", + " sizes=[\"HV_width\", \"HV_height\", 0],\n", + " name=\"HV\",\n", + " material=\"copper\",\n", + ")\n", + "\n", + "region = m2d.modeler.create_region(pad_percent=[20, 10, 0, 10])\n", + "\n", + "# ## Assign boundary condition\n", + "#\n", + "# Assign vector potential to zero on all region boundaries. This makes x=0 edge a symmetry boundary.\n", + "\n", + "m2d.assign_vector_potential(assignment=region.edges, boundary=\"VectorPotential1\")" + ] + }, + { + "cell_type": "markdown", + "id": "d52f21f3", + "metadata": {}, + "source": [ + "## Create initial mesh settings\n", + "\n", + "Assign a relatively dense mesh to all objects to ensure that the energy is calculated accurately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "067e59e9", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.mesh.assign_length_mesh(\n", + " assignment=[\"core\", \"Region\", \"LV\", \"HV\"],\n", + " maximum_length=50,\n", + " maximum_elements=None,\n", + " name=\"all_objects\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8b32967d", + "metadata": {}, + "source": [ + "## Define excitations\n", + "\n", + "Assign the same current in amp-turns but in opposite directions to the HV and LV windings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0e06bab", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.assign_current(assignment=lv, amplitude=\"Amp_turns\", name=\"LV\")\n", + "m2d.assign_current(assignment=hv, amplitude=\"Amp_turns\", name=\"HV\", swap_direction=True)" + ] + }, + { + "cell_type": "markdown", + "id": "15477968", + "metadata": {}, + "source": [ + "## Create and analyze setup\n", + "\n", + "Create and analyze the setup. Set the number of minimum passes to 3 to ensure accuracy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd92ccae", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.create_setup(name=\"Setup1\", MinimumPasses=3)\n", + "m2d.analyze_setup(use_auto_settings=False, cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "93af324d", + "metadata": {}, + "source": [ + "## Calculate transformer leakage inductance and reactance\n", + "\n", + "Calculate transformer leakage inductance from the magnetic energy with PyAEDT advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04820629", + "metadata": {}, + "outputs": [], + "source": [ + "leakage_inductance = {\n", + " \"name\": \"Leakage_inductance\",\n", + " \"description\": \"Leakage inductance from the magnetic energy\",\n", + " \"design_type\": [\"Maxwell 2D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Distance\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Line\"],\n", + " \"operations\": [\n", + " \"Fundamental_Quantity('Energy')\",\n", + " \"EnterSurface('HV')\",\n", + " \"Operation('SurfaceValue')\",\n", + " \"Operation('Integrate')\",\n", + " \"Scalar_Function(FuncValue='HV_mean_turn_length')\",\n", + " \"Operation('*')\",\n", + " \"Fundamental_Quantity('Energy')\",\n", + " \"EnterSurface('LV')\",\n", + " \"Operation('SurfaceValue')\",\n", + " \"Operation('Integrate')\",\n", + " \"Scalar_Function(FuncValue='LV_mean_turn_length')\",\n", + " \"Operation('*')\",\n", + " \"Fundamental_Quantity('Energy')\",\n", + " \"EnterSurface('Region')\",\n", + " \"Operation('SurfaceValue')\",\n", + " \"Operation('Integrate')\",\n", + " \"Scalar_Function(FuncValue='HV_LV_gap_length')\",\n", + " \"Operation('*')\",\n", + " \"Operation('+')\",\n", + " \"Operation('+')\",\n", + " \"Scalar_Constant(2)\",\n", + " \"Operation('*')\",\n", + " \"Scalar_Function(FuncValue='HV_current')\",\n", + " \"Scalar_Function(FuncValue='HV_current')\",\n", + " \"Operation('*')\",\n", + " \"Operation('/')\",\n", + " ],\n", + " \"report\": [\"Data Table\", \"Rectangular Plot\"],\n", + "}\n", + "m2d.post.fields_calculator.add_expression(leakage_inductance, None)\n", + "\n", + "leakage_reactance = {\n", + " \"name\": \"Leakage_reactance\",\n", + " \"description\": \"Leakage reactance from the magnetic energy\",\n", + " \"design_type\": [\"Maxwell 2D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Distance\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Line\"],\n", + " \"operations\": [\n", + " \"NameOfExpression('Leakage_inductance')\",\n", + " \"Scalar_Constant(2)\",\n", + " \"Scalar_Constant(3.14159)\",\n", + " \"Scalar_Function(FuncValue='Frequency')\",\n", + " \"Operation('*')\",\n", + " \"Operation('*')\",\n", + " \"Operation('*')\",\n", + " ],\n", + " \"report\": [\"Data Table\", \"Rectangular Plot\"],\n", + "}\n", + "m2d.post.fields_calculator.add_expression(leakage_reactance, None)\n", + "\n", + "m2d.post.create_report(\n", + " expressions=[\"Leakage_inductance\", \"Leakage_reactance\"],\n", + " report_category=\"Fields\",\n", + " primary_sweep_variable=\"core_width\",\n", + " plot_type=\"Data Table\",\n", + " plot_name=\"Transformer Leakage Inductance\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "02e96d3a", + "metadata": {}, + "source": [ + "## Print leakage inductance and reactance values in AEDT Message Manager" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04ad1677", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.logger.clear_messages()\n", + "m2d.logger.info(\n", + " \"Leakage_inductance = {:.4f}H\".format(\n", + " m2d.post.get_scalar_field_value(quantity=\"Leakage_inductance\")\n", + " )\n", + ")\n", + "m2d.logger.info(\n", + " \"Leakage_reactance = {:.2f}Ohm\".format(\n", + " m2d.post.get_scalar_field_value(quantity=\"Leakage_reactance\")\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "94df4fe3", + "metadata": {}, + "source": [ + "## Plot energy in the simulation domain\n", + "\n", + "Most of the energy is confined in the air between the HV and LV windings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52c7eebc", + "metadata": {}, + "outputs": [], + "source": [ + "energy_field_overlay = m2d.post.create_fieldplot_surface(\n", + " assignment=m2d.modeler.object_names,\n", + " quantity=\"energy\",\n", + " plot_name=\"Energy\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0595e8cc", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9097beaf", + "metadata": {}, + "outputs": [], + "source": [ + "m2d.save_project()\n", + "m2d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "07b1a265", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc1ef220", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/motor/index.rst.txt b/version/dev/_sources/examples/low_frequency/motor/index.rst.txt new file mode 100644 index 00000000..b674f056 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/motor/index.rst.txt @@ -0,0 +1,33 @@ +Motor +===== + +These examples use PyAEDT to show some motor applications. + + +.. grid:: 2 + + .. grid-item-card:: MotorCAD + :padding: 2 2 2 2 + :link: https://motorcad.docs.pyansys.com/version/stable/examples/index.html + :link-type: url + + .. image:: ./_static/motorcad.png + :alt: MotorCAD + :width: 200px + :height: 150px + :align: center + + Links to examples in PyMotorCAD documentation. + + .. grid-item-card:: Motor + :padding: 2 2 2 2 + :link: aedt_motor/index + :link-type: doc + + .. image:: ./_static/motor.png + :alt: Motor + :width: 200px + :height: 150px + :align: center + + Motor workflows using PyAEDT. diff --git a/version/dev/_sources/examples/low_frequency/multiphysics/index.rst.txt b/version/dev/_sources/examples/low_frequency/multiphysics/index.rst.txt new file mode 100644 index 00000000..276cbb17 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/multiphysics/index.rst.txt @@ -0,0 +1,22 @@ +Multiphysics +~~~~~~~~~~~~ + +These examples use PyAEDT to show some multiphysics applications. + +.. grid-item-card:: Maxwell 3D-Icepak electrothermal analysis + :padding: 2 2 2 2 + :link: maxwell_icepak + :link-type: doc + + .. image:: _static/charging.png + :alt: Charging + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up a simple Maxwell design consisting of a coil and a ferrite core. + +.. toctree:: + :hidden: + + maxwell_icepak \ No newline at end of file diff --git a/version/dev/_sources/examples/low_frequency/multiphysics/maxwell_icepak.ipynb.txt b/version/dev/_sources/examples/low_frequency/multiphysics/maxwell_icepak.ipynb.txt new file mode 100644 index 00000000..3d5b9ecc --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/multiphysics/maxwell_icepak.ipynb.txt @@ -0,0 +1,658 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4a2f318a", + "metadata": {}, + "source": [ + "# Maxwell 3D-Icepak electrothermal analysis\n", + "\n", + "This example uses PyAEDT to set up a simple Maxwell design consisting of a coil and a ferrite core.\n", + "Coil current is set to 100A, and coil resistance and ohmic loss are analyzed.\n", + "Ohmic loss is mapped to Icepak, and a thermal analysis is performed.\n", + "Icepak calculates a temperature distribution, and it is mapped back to Maxwell (2-way coupling).\n", + "Coil resistance and ohmic loss are analyzed again in Maxwell. Results are printed in AEDT Message Manager.\n", + "\n", + "Keywords: **Multiphysics**, **Maxwell**, **Icepak**, **Wireless Charging**.\n", + "\n", + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e047e1cd", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cb34424", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core\n", + "from ansys.aedt.core.generic.constants import AXIS" + ] + }, + { + "cell_type": "markdown", + "id": "543192be", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aeae5ec4", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "4c2e6ed0", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e8b1900", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "920eed19", + "metadata": {}, + "source": [ + "## Launch application\n", + "\n", + "The syntax for different applications in AEDT differ\n", + "only in the name of the class. This template uses\n", + "the ``Hfss()`` class. Modify this text as needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d575f42", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"Maxwell-Icepak-2way-Coupling\")\n", + "maxwell_design_name = \"1 Maxwell\"\n", + "icepak_design_name = \"2 Icepak\"\n", + "\n", + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=project_name,\n", + " design=maxwell_design_name,\n", + " solution_type=\"EddyCurrent\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c607928f", + "metadata": {}, + "source": [ + "## Set up model\n", + "\n", + "Create the coil, coil terminal, core, and region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4021eb7", + "metadata": {}, + "outputs": [], + "source": [ + "coil = m3d.modeler.create_rectangle(\n", + " orientation=\"XZ\", origin=[70, 0, -11], sizes=[11, 110], name=\"Coil\"\n", + ")\n", + "\n", + "coil.sweep_around_axis(axis=AXIS.Z)\n", + "\n", + "coil_terminal = m3d.modeler.create_rectangle(\n", + " orientation=\"XZ\", origin=[70, 0, -11], sizes=[11, 110], name=\"Coil_terminal\"\n", + ")\n", + "\n", + "core = m3d.modeler.create_rectangle(\n", + " orientation=\"XZ\", origin=[45, 0, -18], sizes=[7, 160], name=\"Core\"\n", + ")\n", + "core.sweep_around_axis(axis=AXIS.Z)\n", + "\n", + "# Magnetic flux is not concentrated by the core in +z-direction. Therefore, more padding is needed in that direction.\n", + "region = m3d.modeler.create_region(pad_percent=[20, 20, 20, 20, 500, 100])" + ] + }, + { + "cell_type": "markdown", + "id": "ee7d32f2", + "metadata": {}, + "source": [ + "### Create and assign material\n", + "\n", + "Create a new cooper material: Copper AWG40 Litz wire, strand diameter = 0.08mm,\n", + "24 parallel strands. Then assign materials: Assign the coil to AWG40 copper,\n", + "the core to ferrite, and the region to vacuum." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8e7283c", + "metadata": {}, + "outputs": [], + "source": [ + "no_strands = 24\n", + "strand_diameter = 0.08\n", + "\n", + "cu_litz = m3d.materials.duplicate_material(\"copper\", \"copper_litz\")\n", + "cu_litz.stacking_type = \"Litz Wire\"\n", + "cu_litz.wire_diameter = str(strand_diameter) + \"mm\"\n", + "cu_litz.wire_type = \"Round\"\n", + "cu_litz.strand_number = no_strands\n", + "\n", + "m3d.assign_material(region.name, \"vacuum\")\n", + "m3d.assign_material(coil.name, \"copper_litz\")\n", + "m3d.assign_material(core.name, \"ferrite\")" + ] + }, + { + "cell_type": "markdown", + "id": "30523f82", + "metadata": {}, + "source": [ + "Assign coil current. The coil consists of 20 turns. The total current is 10A.\n", + "Note that each coil turn consists of 24 parallel Litz strands as indicated earlier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1bb8b9da", + "metadata": {}, + "outputs": [], + "source": [ + "no_turns = 20\n", + "coil_current = 10\n", + "m3d.assign_coil([\"Coil_terminal\"], conductors_number=no_turns, name=\"Coil_terminal\")\n", + "m3d.assign_winding(is_solid=False, current=coil_current, name=\"Winding1\")\n", + "\n", + "m3d.add_winding_coils(assignment=\"Winding1\", coils=[\"Coil_terminal\"])" + ] + }, + { + "cell_type": "markdown", + "id": "6a7cc4e2", + "metadata": {}, + "source": [ + "## Assign mesh operations\n", + "\n", + "Mesh operations are not necessary in the eddy current solver because of auto-adaptive meshing.\n", + "However, with appropriate mesh operations, less adaptive passes are needed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2d1d583", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.mesh.assign_length_mesh(\n", + " [\"Core\"], maximum_length=15, maximum_elements=None, name=\"Inside_Core\"\n", + ")\n", + "m3d.mesh.assign_length_mesh(\n", + " [\"Coil\"], maximum_length=30, maximum_elements=None, name=\"Inside_Coil\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cf2a0a7a", + "metadata": {}, + "source": [ + "Set conductivity as a function of temperature. Resistivity increases by 0.393% per K." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d19674d6", + "metadata": {}, + "outputs": [], + "source": [ + "cu_resistivity_temp_coefficient = 0.00393\n", + "cu_litz.conductivity.add_thermal_modifier_free_form(\n", + " \"1.0/(1.0+{}*(Temp-20))\".format(cu_resistivity_temp_coefficient)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "347636a2", + "metadata": {}, + "source": [ + "## Set object temperature and enable feedback\n", + "\n", + "Set the temperature of the objects to the default temperature (22 degrees C)\n", + "and enable temperature feedback for two-way coupling." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb913e3d", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.set_objects_temperature([\"Coil\"], ambient_temperature=22)" + ] + }, + { + "cell_type": "markdown", + "id": "5c17c009", + "metadata": {}, + "source": [ + "## Assign matrix\n", + "\n", + "Assign matrix for resistance and inductance calculation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdb48a95", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.assign_matrix([\"Winding1\"], matrix_name=\"Matrix1\")" + ] + }, + { + "cell_type": "markdown", + "id": "50638f34", + "metadata": {}, + "source": [ + "## Create and analyze simulation setup\n", + "\n", + "The simulation frequency is 150 kHz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a7bcf5d", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m3d.create_setup(name=\"Setup1\")\n", + "setup.props[\"Frequency\"] = \"150kHz\"\n", + "m3d.analyze_setup(\"Setup1\")" + ] + }, + { + "cell_type": "markdown", + "id": "f98ae4b3", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Calculate analytical DC resistance and compare it with the simulated coil\n", + "resistance. Print them in AEDT Message Manager, along with the ohmic loss in\n", + "coil before the temperature feedback." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4760fcd", + "metadata": {}, + "outputs": [], + "source": [ + "report = m3d.post.create_report(expressions=\"Matrix1.R(Winding1,Winding1)\")\n", + "solution = report.get_solution_data()\n", + "resistance = solution.data_magnitude()[0]\n", + "\n", + "report_loss = m3d.post.create_report(expressions=\"StrandedLossAC\")\n", + "solution_loss = report_loss.get_solution_data()\n", + "em_loss = solution_loss.data_magnitude()[0]\n", + "\n", + "# Analytical calculation of the DC resistance of the coil\n", + "cu_cond = float(cu_litz.conductivity.value)\n", + "# Average radius of a coil turn = 0.125m\n", + "l_conductor = no_turns * 2 * 0.125 * 3.1415\n", + "# R = resistivity * length / area / no_strand\n", + "r_analytical_DC = (\n", + " (1.0 / cu_cond)\n", + " * l_conductor\n", + " / (3.1415 * (strand_diameter / 1000 / 2) ** 2)\n", + " / no_strands\n", + ")\n", + "\n", + "# Print results in AEDT Message Manager\n", + "m3d.logger.info(\n", + " \"*******Coil analytical DC resistance = {:.2f}Ohm\".format(r_analytical_DC)\n", + ")\n", + "m3d.logger.info(\n", + " \"*******Coil resistance at 150kHz BEFORE temperature feedback = {:.2f}Ohm\".format(\n", + " resistance\n", + " )\n", + ")\n", + "m3d.logger.info(\n", + " \"*******Ohmic loss in coil BEFORE temperature feedback = {:.2f}W\".format(\n", + " em_loss / 1000\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "6f07ecfe", + "metadata": {}, + "source": [ + "## Insert Icepak design\n", + "\n", + "Insert Icepak design, copy solid objects from Maxwell 3D, and modify region dimensions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72b009c4", + "metadata": {}, + "outputs": [], + "source": [ + "ipk = ansys.aedt.core.Icepak(design=icepak_design_name, version=AEDT_VERSION)\n", + "ipk.copy_solid_bodies_from(m3d, no_pec=False)\n", + "\n", + "# Set domain dimensions suitable for natural convection using the diameter of the coil\n", + "ipk.modeler[\"Region\"].delete()\n", + "coil_dim = coil.bounding_dimension[0]\n", + "ipk.modeler.create_region(0, False)\n", + "ipk.modeler.edit_region_dimensions(\n", + " [coil_dim / 2, coil_dim / 2, coil_dim / 2, coil_dim / 2, coil_dim * 2, coil_dim]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "33f27eea", + "metadata": {}, + "source": [ + "## Map coil losses\n", + "\n", + "Map ohmic losses from Maxwell 3D to the Icepak design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c37dcc4", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assign_em_losses(\n", + " design=\"1 Maxwell\",\n", + " setup=m3d.setups[0].name,\n", + " sweep=\"LastAdaptive\",\n", + " assignment=[\"Coil\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7279ff37", + "metadata": {}, + "source": [ + "### Define boundary conditions\n", + "\n", + "Assign the opening." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d1d6b97", + "metadata": {}, + "outputs": [], + "source": [ + "faces = ipk.modeler[\"Region\"].faces\n", + "face_names = [face.id for face in faces]\n", + "ipk.assign_free_opening(face_names, boundary_name=\"Opening1\")" + ] + }, + { + "cell_type": "markdown", + "id": "8527384a", + "metadata": {}, + "source": [ + "### Assign monitor\n", + "\n", + "Assign the temperature monitor on the coil surface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5288e88", + "metadata": {}, + "outputs": [], + "source": [ + "temp_monitor = ipk.assign_point_monitor([70, 0, 0], monitor_name=\"PointMonitor1\")" + ] + }, + { + "cell_type": "markdown", + "id": "67260801", + "metadata": {}, + "source": [ + "Set up Icepak solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fc403b1", + "metadata": {}, + "outputs": [], + "source": [ + "solution_setup = ipk.create_setup()\n", + "solution_setup.props[\"Convergence Criteria - Max Iterations\"] = 50\n", + "solution_setup.props[\"Flow Regime\"] = \"Turbulent\"\n", + "solution_setup.props[\"Turbulent Model Eqn\"] = \"ZeroEquation\"\n", + "solution_setup.props[\"Radiation Model\"] = \"Discrete Ordinates Model\"\n", + "solution_setup.props[\"Include Flow\"] = True\n", + "solution_setup.props[\"Include Gravity\"] = True\n", + "solution_setup.props[\"Solution Initialization - Z Velocity\"] = \"0.0005m_per_sec\"\n", + "solution_setup.props[\"Convergence Criteria - Flow\"] = 0.0005\n", + "solution_setup.props[\"Flow Iteration Per Radiation Iteration\"] = \"5\"" + ] + }, + { + "cell_type": "markdown", + "id": "8d174b99", + "metadata": {}, + "source": [ + "## Add two-way coupling and solve the project\n", + "\n", + "Enable mapping temperature distribution back to Maxwell 3D. The default number\n", + "for Maxwell <–> Icepak iterations is 2. However, for increased accuracy,\n", + "you can increate the value for the ``number_of_iterations`` parameter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54a79eb9", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.assign_2way_coupling()\n", + "ipk.analyze_setup(name=solution_setup.name)" + ] + }, + { + "cell_type": "markdown", + "id": "e28535fc", + "metadata": {}, + "source": [ + "## Postprocess\n", + "\n", + "Plot temperature on the object surfaces." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed308b80", + "metadata": {}, + "outputs": [], + "source": [ + "surface_list = []\n", + "for name in [\"Coil\", \"Core\"]:\n", + " surface_list.extend(ipk.modeler.get_object_faces(name))\n", + "\n", + "surf_temperature = ipk.post.create_fieldplot_surface(\n", + " surface_list, quantity=\"SurfTemperature\", plot_name=\"Surface Temperature\"\n", + ")\n", + "\n", + "velocity_cutplane = ipk.post.create_fieldplot_cutplane(\n", + " assignment=[\"Global:XZ\"], quantity=\"Velocity Vectors\", plot_name=\"Velocity Vectors\"\n", + ")\n", + "\n", + "surf_temperature.export_image()\n", + "velocity_cutplane.export_image(orientation=\"right\")\n", + "\n", + "report_temp = ipk.post.create_report(\n", + " expressions=\"PointMonitor1.Temperature\", primary_sweep_variable=\"X\"\n", + ")\n", + "solution_temp = report_temp.get_solution_data()\n", + "temp = solution_temp.data_magnitude()[0]\n", + "m3d.logger.info(\"*******Coil temperature = {:.2f}deg C\".format(temp))" + ] + }, + { + "cell_type": "markdown", + "id": "bb2809d7", + "metadata": {}, + "source": [ + "### Get new resistance from Maxwell 3D\n", + "\n", + "The temperature of the coil increases, and consequently the coil resistance increases." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0db00d96", + "metadata": {}, + "outputs": [], + "source": [ + "report_new = m3d.post.create_report(expressions=\"Matrix1.R(Winding1,Winding1)\")\n", + "solution_new = report_new.get_solution_data()\n", + "resistance_new = solution_new.data_magnitude()[0]\n", + "resistance_increase = (resistance_new - resistance) / resistance * 100\n", + "\n", + "report_loss_new = m3d.post.create_report(expressions=\"StrandedLossAC\")\n", + "solution_loss_new = report_loss_new.get_solution_data()\n", + "em_loss_new = solution_loss_new.data_magnitude()[0]\n", + "\n", + "m3d.logger.info(\n", + " \"*******Coil resistance at 150kHz AFTER temperature feedback = {:.2f}Ohm\".format(\n", + " resistance_new\n", + " )\n", + ")\n", + "m3d.logger.info(\n", + " \"*******Coil resistance increased by {:.2f}%\".format(resistance_increase)\n", + ")\n", + "m3d.logger.info(\n", + " \"*******Ohmic loss in coil AFTER temperature feedback = {:.2f}W\".format(\n", + " em_loss_new / 1000\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b830fb9c", + "metadata": {}, + "source": [ + "### Save project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "960382a4", + "metadata": {}, + "outputs": [], + "source": [ + "ipk.save_project()\n", + "ipk.release_desktop()\n", + "time.sleep(3) # Allow AEDT to shut down before cleaning the temporary project folder." + ] + }, + { + "cell_type": "markdown", + "id": "a4f685a9", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell removes\n", + "all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74add1ef", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/team_problem/asymmetric_conductor.ipynb.txt b/version/dev/_sources/examples/low_frequency/team_problem/asymmetric_conductor.ipynb.txt new file mode 100644 index 00000000..886136a8 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/team_problem/asymmetric_conductor.ipynb.txt @@ -0,0 +1,944 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f6d2b64", + "metadata": {}, + "source": [ + "# Asymmetric conductor analysis\n", + "\n", + "This example uses PyAEDT to set up the TEAM 7 problem for an asymmetric\n", + "conductor with a hole and solve it using the Maxwell 3D eddy current solver.\n", + "For more information on this problem, see this\n", + "[paper](https://www.compumag.org/wp/wp-content/uploads/2018/06/problem7.pdf).\n", + "\n", + "Keywords: **Maxwell 3D**, **Asymmetric conductor**." + ] + }, + { + "cell_type": "markdown", + "id": "737bdacc", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96516e26", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41e66149", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from ansys.aedt.core import Maxwell3d\n", + "from ansys.aedt.core.generic.general_methods import write_csv" + ] + }, + { + "cell_type": "markdown", + "id": "8a3f9918", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ff2be33", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "1299fffa", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b0ea8e6", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "446c3d92", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 3D\n", + "\n", + "Create an instance of the ``Maxwell3d`` class named ``m3d`` by providing\n", + "the project and design names, the solver, and the version." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "709edb76", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"COMPUMAG2.aedt\")\n", + "m3d = Maxwell3d(\n", + " project=project_name,\n", + " design=\"TEAM_7_Asymmetric_Conductor\",\n", + " solution_type=\"EddyCurrent\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "m3d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "8b65ee00", + "metadata": {}, + "source": [ + "## Add Maxwell 3D setup\n", + "\n", + "Add a Maxwell 3D setup with frequency points at DC, 50 Hz, and 200Hz.\n", + "Otherwise, the default PyAEDT setup values are used. To approximate a DC field in the\n", + "eddy current solver, use a low frequency value. Second-order shape functions improve\n", + "the smoothness of the induced currents in the plate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1ed4cc7", + "metadata": {}, + "outputs": [], + "source": [ + "dc_freq = 0.1\n", + "stop_freq = 50\n", + "\n", + "setup = m3d.create_setup(name=\"Setup1\")\n", + "setup.props[\"Frequency\"] = \"200Hz\"\n", + "setup.props[\"HasSweepSetup\"] = True\n", + "setup.add_eddy_current_sweep(\n", + " range_type=\"LinearStep\",\n", + " start=dc_freq,\n", + " end=stop_freq,\n", + " count=stop_freq - dc_freq,\n", + " clear=True,\n", + ")\n", + "setup.props[\"UseHighOrderShapeFunc\"] = True\n", + "setup.props[\"PercentError\"] = 0.4" + ] + }, + { + "cell_type": "markdown", + "id": "ca88fa27", + "metadata": {}, + "source": [ + "## Define coil dimensions\n", + "\n", + "Define coil dimensions as shown on the TEAM7 drawing of the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7be9a873", + "metadata": {}, + "outputs": [], + "source": [ + "coil_external = 150 + 25 + 25\n", + "coil_internal = 150\n", + "coil_r1 = 25\n", + "coil_r2 = 50\n", + "coil_thk = coil_r2 - coil_r1\n", + "coil_height = 100\n", + "coil_centre = [294 - 25 - 150 / 2, 25 + 150 / 2, 19 + 30 + 100 / 2]" + ] + }, + { + "cell_type": "markdown", + "id": "499ac453", + "metadata": {}, + "source": [ + "Use expressions to construct the three dimensions needed to describe the midpoints of\n", + "the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b2abc54", + "metadata": {}, + "outputs": [], + "source": [ + "dim1 = coil_internal / 2 + (coil_external - coil_internal) / 4\n", + "dim2 = coil_internal / 2 - coil_r1\n", + "dim3 = dim2 + np.sqrt(((coil_r1 + (coil_r2 - coil_r1) / 2) ** 2) / 2)" + ] + }, + { + "cell_type": "markdown", + "id": "c5466fe8", + "metadata": {}, + "source": [ + "Use coordinates to draw a polyline along which to sweep the coil cross sections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df809d58", + "metadata": {}, + "outputs": [], + "source": [ + "P1 = [dim1, -dim2, 0]\n", + "P2 = [dim1, dim2, 0]\n", + "P3 = [dim3, dim3, 0]\n", + "P4 = [dim2, dim1, 0]" + ] + }, + { + "cell_type": "markdown", + "id": "9bf0fd7e", + "metadata": {}, + "source": [ + "## Create coordinate system for positioning coil" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a476bfbf", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.create_coordinate_system(\n", + " origin=coil_centre, mode=\"view\", view=\"XY\", name=\"Coil_CS\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "7e4cbe20", + "metadata": {}, + "source": [ + "## Create polyline\n", + "\n", + "Create a polyline. One quarter of the coil is modeled by sweeping a 2D sheet along a polyline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5f6eb6c", + "metadata": {}, + "outputs": [], + "source": [ + "test = m3d.modeler.create_polyline(\n", + " points=[P1, P2, P3, P4], segment_type=[\"Line\", \"Arc\"], name=\"Coil\"\n", + ")\n", + "test.set_crosssection_properties(type=\"Rectangle\", width=coil_thk, height=coil_height)" + ] + }, + { + "cell_type": "markdown", + "id": "d9d4fa50", + "metadata": {}, + "source": [ + "## Duplicate and unite polyline to create full coil" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cae7144e", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.duplicate_around_axis(\n", + " assignment=\"Coil\",\n", + " axis=\"Global\",\n", + " angle=90,\n", + " clones=4,\n", + " create_new_objects=True,\n", + " is_3d_comp=False,\n", + ")\n", + "m3d.modeler.unite(\"Coil, Coil_1, Coil_2\")\n", + "m3d.modeler.unite(\"Coil, Coil_3\")\n", + "m3d.modeler.fit_all()" + ] + }, + { + "cell_type": "markdown", + "id": "0236eb08", + "metadata": {}, + "source": [ + "## Assign material and if solution is allowed inside coil\n", + "\n", + "Assign the material ``Cooper`` from the Maxwell internal library to the coil and\n", + "allow a solution inside the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8425d8f5", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.assign_material(assignment=\"Coil\", material=\"Copper\")\n", + "m3d.solve_inside(\"Coil\")" + ] + }, + { + "cell_type": "markdown", + "id": "5646759e", + "metadata": {}, + "source": [ + "## Create terminal\n", + "\n", + "Create a terminal for the coil from a cross-section that is split and one half deleted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "674223ff", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.section(assignment=\"Coil\", plane=\"YZ\")\n", + "m3d.modeler.separate_bodies(assignment=\"Coil_Section1\")\n", + "m3d.modeler.delete(assignment=\"Coil_Section1_Separate1\")" + ] + }, + { + "cell_type": "markdown", + "id": "0cd58d61", + "metadata": {}, + "source": [ + "## Add variable for coil excitation\n", + "\n", + "Add a design variable for coil excitation. The NB units here are AmpereTurns." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fdca3ad", + "metadata": {}, + "outputs": [], + "source": [ + "Coil_Excitation = 2742\n", + "m3d[\"Coil_Excitation\"] = str(Coil_Excitation) + \"A\"\n", + "m3d.assign_current(assignment=\"Coil_Section1\", amplitude=\"Coil_Excitation\", solid=False)\n", + "m3d.modeler.set_working_coordinate_system(\"Global\")" + ] + }, + { + "cell_type": "markdown", + "id": "a8c40936", + "metadata": {}, + "source": [ + "## Add material\n", + "\n", + "Add a material named ``team3_aluminium``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86896ead", + "metadata": {}, + "outputs": [], + "source": [ + "mat = m3d.materials.add_material(\"team7_aluminium\")\n", + "mat.conductivity = 3.526e7" + ] + }, + { + "cell_type": "markdown", + "id": "eed41e39", + "metadata": {}, + "source": [ + "## Model aluminium plate with a hole\n", + "\n", + "Model the aluminium plate with a hole by subtracting two rectangular cuboids." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fbadfbad", + "metadata": {}, + "outputs": [], + "source": [ + "plate = m3d.modeler.create_box(\n", + " origin=[0, 0, 0], sizes=[294, 294, 19], name=\"Plate\", material=\"team7_aluminium\"\n", + ")\n", + "m3d.modeler.fit_all()\n", + "hole = m3d.modeler.create_box(origin=[18, 18, 0], sizes=[108, 108, 19], name=\"Hole\")\n", + "m3d.modeler.subtract(blank_list=\"Plate\", tool_list=[\"Hole\"], keep_originals=False)" + ] + }, + { + "cell_type": "markdown", + "id": "92e56355", + "metadata": {}, + "source": [ + "## Draw background region\n", + "\n", + "Draw a background region that uses the default properties for an air region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f963dd3", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.create_air_region(\n", + " x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=100\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3e8b0ddf", + "metadata": {}, + "source": [ + "## Adjust eddy effects for plate and coil\n", + "\n", + "Adjust the eddy effects for the plate and coil by turning off displacement currents\n", + "for all parts. The setting for the eddy effect is ignored for the stranded conductor type\n", + "used in the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8f9ad94", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.eddy_effects_on(assignment=\"Plate\")\n", + "m3d.eddy_effects_on(\n", + " assignment=[\"Coil\", \"Region\", \"Line_A1_B1mesh\", \"Line_A2_B2mesh\"],\n", + " enable_eddy_effects=False,\n", + " enable_displacement_current=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "753cd133", + "metadata": {}, + "source": [ + "## Create expression for Z component of B in Gauss\n", + "\n", + "Create an expression for the Z component of B in Gauss using PyAEDT advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6e29101", + "metadata": {}, + "outputs": [], + "source": [ + "bz = {\n", + " \"name\": \"Bz\",\n", + " \"description\": \"Z component of B in Gauss\",\n", + " \"design_type\": [\"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Distance\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Line\"],\n", + " \"operations\": [\n", + " \"NameOfExpression('')\",\n", + " \"Operation('ScalarZ')\",\n", + " \"Scalar_Function(FuncValue='Phase')\",\n", + " \"Operation('AtPhase')\",\n", + " \"Scalar_Constant(10000)\",\n", + " \"Operation('*')\",\n", + " \"Operation('Smooth')\",\n", + " ],\n", + " \"report\": [\"Field_3D\"],\n", + "}\n", + "m3d.post.fields_calculator.add_expression(bz, None)" + ] + }, + { + "cell_type": "markdown", + "id": "10e7af3e", + "metadata": {}, + "source": [ + "## Draw two lines along which to plot Bz\n", + "\n", + "Draw two lines along which to plot Bz. The following code also adds a small cylinder\n", + "to refine the mesh locally around each line." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94ced108", + "metadata": {}, + "outputs": [], + "source": [ + "lines = [\"Line_A1_B1\", \"Line_A2_B2\"]\n", + "mesh_diameter = \"2mm\"\n", + "\n", + "line_points_1 = [[\"0mm\", \"72mm\", \"34mm\"], [\"288mm\", \"72mm\", \"34mm\"]]\n", + "polyline = m3d.modeler.create_polyline(points=line_points_1, name=lines[0])\n", + "l1_mesh = m3d.modeler.create_polyline(points=line_points_1, name=lines[0] + \"mesh\")\n", + "l1_mesh.set_crosssection_properties(type=\"Circle\", width=mesh_diameter)\n", + "\n", + "line_points_2 = [[\"0mm\", \"144mm\", \"34mm\"], [\"288mm\", \"144mm\", \"34mm\"]]\n", + "polyline2 = m3d.modeler.create_polyline(points=line_points_2, name=lines[1])\n", + "l2_mesh = m3d.modeler.create_polyline(points=line_points_2, name=lines[1] + \"mesh\")\n", + "l2_mesh.set_crosssection_properties(type=\"Circle\", width=mesh_diameter)" + ] + }, + { + "cell_type": "markdown", + "id": "bac9e978", + "metadata": {}, + "source": [ + "Published measurement results are included with this script via the following list.\n", + "Test results are used to create text files for import into a rectangular plot\n", + "and to overlay simulation results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e67fb5a4", + "metadata": {}, + "outputs": [], + "source": [ + "project_dir = temp_folder.name\n", + "dataset = [\n", + " \"Bz A1_B1 000 0\",\n", + " \"Bz A1_B1 050 0\",\n", + " \"Bz A1_B1 050 90\",\n", + " \"Bz A1_B1 200 0\",\n", + " \"Bz A1_B1 200 90\",\n", + " \"Bz A2_B2 050 0\",\n", + " \"Bz A2_B2 050 90\",\n", + " \"Bz A2_B2 200 0\",\n", + " \"Bz A2_B2 200 90\",\n", + "]\n", + "header = [\"Distance [mm]\", \"Bz [Tesla]\"]\n", + "\n", + "line_length = [\n", + " 0,\n", + " 18,\n", + " 36,\n", + " 54,\n", + " 72,\n", + " 90,\n", + " 108,\n", + " 126,\n", + " 144,\n", + " 162,\n", + " 180,\n", + " 198,\n", + " 216,\n", + " 234,\n", + " 252,\n", + " 270,\n", + " 288,\n", + "]\n", + "data = [\n", + " [\n", + " -6.667,\n", + " -7.764,\n", + " -8.707,\n", + " -8.812,\n", + " -5.870,\n", + " 8.713,\n", + " 50.40,\n", + " 88.47,\n", + " 100.9,\n", + " 104.0,\n", + " 104.8,\n", + " 104.9,\n", + " 104.6,\n", + " 103.1,\n", + " 97.32,\n", + " 75.19,\n", + " 29.04,\n", + " ],\n", + " [\n", + " 4.90,\n", + " -17.88,\n", + " -22.13,\n", + " -20.19,\n", + " -15.67,\n", + " 0.36,\n", + " 43.64,\n", + " 78.11,\n", + " 71.55,\n", + " 60.44,\n", + " 53.91,\n", + " 52.62,\n", + " 53.81,\n", + " 56.91,\n", + " 59.24,\n", + " 52.78,\n", + " 27.61,\n", + " ],\n", + " [\n", + " -1.16,\n", + " 2.84,\n", + " 4.15,\n", + " 4.00,\n", + " 3.07,\n", + " 2.31,\n", + " 1.89,\n", + " 4.97,\n", + " 12.61,\n", + " 14.15,\n", + " 13.04,\n", + " 12.40,\n", + " 12.05,\n", + " 12.27,\n", + " 12.66,\n", + " 9.96,\n", + " 2.36,\n", + " ],\n", + " [\n", + " -3.63,\n", + " -18.46,\n", + " -23.62,\n", + " -21.59,\n", + " -16.09,\n", + " 0.23,\n", + " 44.35,\n", + " 75.53,\n", + " 63.42,\n", + " 53.20,\n", + " 48.66,\n", + " 47.31,\n", + " 48.31,\n", + " 51.26,\n", + " 53.61,\n", + " 46.11,\n", + " 24.96,\n", + " ],\n", + " [\n", + " -1.38,\n", + " 1.20,\n", + " 2.15,\n", + " 1.63,\n", + " 1.10,\n", + " 0.27,\n", + " -2.28,\n", + " -1.40,\n", + " 4.17,\n", + " 3.94,\n", + " 4.86,\n", + " 4.09,\n", + " 3.69,\n", + " 4.60,\n", + " 3.48,\n", + " 4.10,\n", + " 0.98,\n", + " ],\n", + " [\n", + " -1.83,\n", + " -8.50,\n", + " -13.60,\n", + " -15.21,\n", + " -14.48,\n", + " -5.62,\n", + " 28.77,\n", + " 60.34,\n", + " 61.84,\n", + " 56.64,\n", + " 53.40,\n", + " 52.36,\n", + " 53.93,\n", + " 56.82,\n", + " 59.48,\n", + " 52.08,\n", + " 26.56,\n", + " ],\n", + " [\n", + " -1.63,\n", + " -0.60,\n", + " -0.43,\n", + " 0.11,\n", + " 1.26,\n", + " 3.40,\n", + " 6.53,\n", + " 10.25,\n", + " 11.83,\n", + " 11.83,\n", + " 11.01,\n", + " 10.58,\n", + " 10.80,\n", + " 10.54,\n", + " 10.62,\n", + " 9.03,\n", + " 1.79,\n", + " ],\n", + " [\n", + " -0.86,\n", + " -7.00,\n", + " -11.58,\n", + " -13.36,\n", + " -13.77,\n", + " -6.74,\n", + " 24.63,\n", + " 53.19,\n", + " 54.89,\n", + " 50.72,\n", + " 48.03,\n", + " 47.13,\n", + " 48.25,\n", + " 51.35,\n", + " 53.35,\n", + " 45.37,\n", + " 24.01,\n", + " ],\n", + " [\n", + " -1.35,\n", + " -0.71,\n", + " -0.81,\n", + " -0.67,\n", + " 0.15,\n", + " 1.39,\n", + " 2.67,\n", + " 3.00,\n", + " 4.01,\n", + " 3.80,\n", + " 4.00,\n", + " 3.02,\n", + " 2.20,\n", + " 2.78,\n", + " 1.58,\n", + " 1.37,\n", + " 0.93,\n", + " ],\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "c9127241", + "metadata": {}, + "source": [ + "## Write dataset values to a CSV file\n", + "\n", + "Dataset details are used to encode test parameters in the text files.\n", + "For example, ``Bz A1_B1 050 0`` is the Z component of flux density ``B``\n", + "along line ``A1_B1`` at 50 Hz and 0 deg." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b7d3317", + "metadata": {}, + "outputs": [], + "source": [ + "line_length.insert(0, header[0])\n", + "for i in range(len(dataset)):\n", + " data[i].insert(0, header[1])\n", + " ziplist = zip(line_length, data[i])\n", + " file_path = os.path.join(temp_folder.name, str(dataset[i]) + \".csv\")\n", + " write_csv(output_file=file_path, list_data=ziplist)" + ] + }, + { + "cell_type": "markdown", + "id": "c35a10ed", + "metadata": {}, + "source": [ + "## Create rectangular plots and import test data into report\n", + "\n", + "Create rectangular plots, using text file encoding to control their formatting.\n", + "Import test data into the correct plot and overlay with the simulation results.\n", + "Variations for a DC plot must have a different frequency and phase than the other plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02f299c3", + "metadata": {}, + "outputs": [], + "source": [ + "for item in range(len(dataset)):\n", + " if item % 2 == 0:\n", + " t = dataset[item]\n", + " plot_name = t[0:3] + \"Along the Line\" + t[2:9] + \", \" + t[9:12] + \"Hz\"\n", + " if t[9:12] == \"000\":\n", + " variations = {\n", + " \"Distance\": [\"All\"],\n", + " \"Freq\": [str(dc_freq) + \"Hz\"],\n", + " \"Phase\": [\"0deg\"],\n", + " \"Coil_Excitation\": [\"All\"],\n", + " }\n", + " else:\n", + " variations = {\n", + " \"Distance\": [\"All\"],\n", + " \"Freq\": [t[9:12] + \"Hz\"],\n", + " \"Phase\": [\"0deg\", \"90deg\"],\n", + " \"Coil_Excitation\": [\"All\"],\n", + " }\n", + " report = m3d.post.create_report(\n", + " plot_name=plot_name,\n", + " report_category=\"Fields\",\n", + " context=\"Line_\" + t[3:8],\n", + " primary_sweep_variable=\"Distance\",\n", + " variations=variations,\n", + " expressions=t[0:2],\n", + " )\n", + " file_path = os.path.join(temp_folder.name, str(dataset[i]) + \".csv\")\n", + " report.import_traces(input_file=file_path, plot_name=plot_name)" + ] + }, + { + "cell_type": "markdown", + "id": "ab3b32ed", + "metadata": {}, + "source": [ + "Analyze project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f816b62e", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "61035312", + "metadata": {}, + "source": [ + "## Create plots of induced current and flux density on surface of plate\n", + "\n", + "Create two plots of the induced current (``Mag_J``) and the flux density (``Mag_B``) on the\n", + "surface of the plate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f48b92", + "metadata": {}, + "outputs": [], + "source": [ + "surf_list = m3d.modeler.get_object_faces(assignment=\"Plate\")\n", + "intrinsic_dict = {\"Freq\": \"200Hz\", \"Phase\": \"0deg\"}\n", + "m3d.post.create_fieldplot_surface(\n", + " assignment=surf_list,\n", + " quantity=\"Mag_J\",\n", + " intrinsics=intrinsic_dict,\n", + " plot_name=\"Mag_J\",\n", + ")\n", + "m3d.post.create_fieldplot_surface(\n", + " assignment=surf_list,\n", + " quantity=\"Mag_B\",\n", + " intrinsics=intrinsic_dict,\n", + " plot_name=\"Mag_B\",\n", + ")\n", + "m3d.post.create_fieldplot_surface(\n", + " assignment=surf_list, quantity=\"Mesh\", intrinsics=intrinsic_dict, plot_name=\"Mesh\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4c122eb5", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4d64a66", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "5a260e02", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7780c1b7", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/team_problem/bath_plate.ipynb.txt b/version/dev/_sources/examples/low_frequency/team_problem/bath_plate.ipynb.txt new file mode 100644 index 00000000..670ec3d0 --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/team_problem/bath_plate.ipynb.txt @@ -0,0 +1,647 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f89d6e97", + "metadata": {}, + "source": [ + "# Bath plate analysis\n", + "\n", + "This example uses PyAEDT to set up the TEAM 3 bath plate problem and\n", + "solve it using the Maxwell 3D eddy current solver.\n", + "# For more information on this problem, see this\n", + "[paper](https://www.compumag.org/wp/wp-content/uploads/2018/06/problem3.pdf).\n", + "\n", + "Keywords: **Maxwell 3D**, **TEAM 3 bath plate**" + ] + }, + { + "cell_type": "markdown", + "id": "6bb7c7ca", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "767fe868", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab7bb4e9", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "b5f7132b", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0fb337a", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "40edc5d7", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad99c147", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "5e2f7641", + "metadata": {}, + "source": [ + "## Launch AEDT and Maxwell 3D\n", + "\n", + "Create an instance of the ``Maxwell3d`` class named ``m3d`` by providing\n", + "the project and design names, the solver, and the version." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5254a135", + "metadata": {}, + "outputs": [], + "source": [ + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=os.path.join(temp_folder.name, \"COMPUMAG.aedt\"),\n", + " design=\"TEAM_3_Bath_Plate\",\n", + " solution_type=\"EddyCurrent\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "uom = m3d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "8318419c", + "metadata": {}, + "source": [ + "## Add variable\n", + "\n", + "Add a design variable named ``Coil_Position`` to use later to adjust the\n", + "position of the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e3e5ef9", + "metadata": {}, + "outputs": [], + "source": [ + "Coil_Position = -20\n", + "m3d[\"Coil_Position\"] = str(Coil_Position) + m3d.modeler.model_units" + ] + }, + { + "cell_type": "markdown", + "id": "df097dc8", + "metadata": {}, + "source": [ + "## Add material\n", + "\n", + "Add a material named ``team3_aluminium`` for the ladder plate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b75cd168", + "metadata": {}, + "outputs": [], + "source": [ + "mat = m3d.materials.add_material(name=\"team3_aluminium\")\n", + "mat.conductivity = 32780000" + ] + }, + { + "cell_type": "markdown", + "id": "8dd04949", + "metadata": {}, + "source": [ + "## Draw background region\n", + "\n", + "Draw a background region that uses the default properties for an air region." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72d38b32", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.create_air_region(\n", + " x_pos=100, y_pos=100, z_pos=100, x_neg=100, y_neg=100, z_neg=100\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "148e8fc0", + "metadata": {}, + "source": [ + "## Draw ladder plate and assign material\n", + "\n", + "Draw a ladder plate and assign it the newly created material ``team3_aluminium``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2ca2c42", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.create_box(\n", + " origin=[-30, -55, 0],\n", + " sizes=[60, 110, -6.35],\n", + " name=\"LadderPlate\",\n", + " material=\"team3_aluminium\",\n", + ")\n", + "m3d.modeler.create_box(origin=[-20, -35, 0], sizes=[40, 30, -6.35], name=\"CutoutTool1\")\n", + "m3d.modeler.create_box(origin=[-20, 5, 0], sizes=[40, 30, -6.35], name=\"CutoutTool2\")\n", + "m3d.modeler.subtract(\n", + " blank_list=\"LadderPlate\",\n", + " tool_list=[\"CutoutTool1\", \"CutoutTool2\"],\n", + " keep_originals=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b4fe1e43", + "metadata": {}, + "source": [ + "## Add mesh refinement to ladder plate" + ] + }, + { + "cell_type": "markdown", + "id": "6ac24c26", + "metadata": {}, + "source": [ + "> **Note:** You can uncomment the following code." + ] + }, + { + "cell_type": "markdown", + "id": "7d2f0d37", + "metadata": {}, + "source": [ + "m3d.mesh.assign_length_mesh(\n", + " assignment=\"LadderPlate\",\n", + " maximum_length=3,\n", + " maximum_elements=None,\n", + " name=\"Ladder_Mesh\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d1a253e4", + "metadata": {}, + "source": [ + "## Draw search coil and assign excitation\n", + "\n", + "Draw a search coil and assign it a ``stranded`` current excitation.\n", + "The stranded type forces the current density to be constant in the coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc9ff32", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.modeler.create_cylinder(\n", + " orientation=\"Z\",\n", + " origin=[0, \"Coil_Position\", 15],\n", + " radius=40,\n", + " height=20,\n", + " name=\"SearchCoil\",\n", + " material=\"copper\",\n", + ")\n", + "m3d.modeler.create_cylinder(\n", + " orientation=\"Z\",\n", + " origin=[0, \"Coil_Position\", 15],\n", + " radius=20,\n", + " height=20,\n", + " name=\"Bore\",\n", + " material=\"copper\",\n", + ")\n", + "m3d.modeler.subtract(blank_list=\"SearchCoil\", tool_list=\"Bore\", keep_originals=False)\n", + "m3d.modeler.section(assignment=\"SearchCoil\", plane=\"YZ\")\n", + "m3d.modeler.separate_bodies(assignment=\"SearchCoil_Section1\")\n", + "m3d.modeler.delete(assignment=\"SearchCoil_Section1_Separate1\")\n", + "m3d.assign_current(\n", + " assignment=[\"SearchCoil_Section1\"],\n", + " amplitude=1260,\n", + " solid=False,\n", + " name=\"SearchCoil_Excitation\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e82896b8", + "metadata": {}, + "source": [ + "## Draw a line for plotting Bz\n", + "\n", + "Draw a line for plotting Bz later. Bz is the Z component of the flux\n", + "density. The following code also adds a small diameter cylinder to refine the\n", + "mesh locally around the line." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6430d8d7", + "metadata": {}, + "outputs": [], + "source": [ + "line_points = [[\"0mm\", \"-55mm\", \"0.5mm\"], [\"0mm\", \"55mm\", \"0.5mm\"]]\n", + "m3d.modeler.create_polyline(points=line_points, name=\"Line_AB\")\n", + "poly = m3d.modeler.create_polyline(points=line_points, name=\"Line_AB_MeshRefinement\")\n", + "poly.set_crosssection_properties(type=\"Circle\", width=\"0.5mm\")" + ] + }, + { + "cell_type": "markdown", + "id": "57ea0371", + "metadata": {}, + "source": [ + "## Add Maxwell 3D setup\n", + "\n", + "Add a Maxwell 3D setup with frequency points at 50 Hz and 200 Hz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d756a856", + "metadata": {}, + "outputs": [], + "source": [ + "setup = m3d.create_setup(name=\"Setup1\")\n", + "setup.props[\"Frequency\"] = \"200Hz\"\n", + "setup.props[\"HasSweepSetup\"] = True\n", + "setup.props[\"MaximumPasses\"] = 1\n", + "setup.add_eddy_current_sweep(\n", + " range_type=\"LinearStep\", start=50, end=200, count=150, clear=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8a8e6f6c", + "metadata": {}, + "source": [ + "## Adjust eddy effects\n", + "\n", + "Adjust eddy effects for the ladder plate and the search coil. The setting for\n", + "eddy effect is ignored for the stranded conductor type used in the search coil." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80c5a639", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.eddy_effects_on(\n", + " assignment=[\"LadderPlate\"],\n", + " enable_eddy_effects=True,\n", + " enable_displacement_current=True,\n", + ")\n", + "m3d.eddy_effects_on(\n", + " assignment=[\"SearchCoil\"],\n", + " enable_eddy_effects=False,\n", + " enable_displacement_current=True,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "32cdd472", + "metadata": {}, + "source": [ + "## Add linear parametric sweep\n", + "\n", + "Add a linear parametric sweep for the two coil positions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3feeb8cf", + "metadata": {}, + "outputs": [], + "source": [ + "sweep_name = \"CoilSweep\"\n", + "param = m3d.parametrics.add(\n", + " variable=\"Coil_Position\",\n", + " start_point=-20,\n", + " end_point=0,\n", + " step=20,\n", + " variation_type=\"LinearStep\",\n", + " name=sweep_name,\n", + ")\n", + "param[\"SaveFields\"] = True\n", + "param[\"CopyMesh\"] = False\n", + "param[\"SolveWithCopiedMeshOnly\"] = True" + ] + }, + { + "cell_type": "markdown", + "id": "f9b18e65", + "metadata": {}, + "source": [ + "## Solve parametric sweep\n", + "\n", + "Solve the parametric sweep directly so that results of all variations are available." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9c6e75e", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "param.analyze(cores=NUM_CORES)" + ] + }, + { + "cell_type": "markdown", + "id": "9898e251", + "metadata": {}, + "source": [ + "## Create expression for Bz\n", + "\n", + "Create an expression for Bz using PyAEDT advanced fields calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f84b2cf2", + "metadata": {}, + "outputs": [], + "source": [ + "bz = {\n", + " \"name\": \"Bz\",\n", + " \"description\": \"Z component of B\",\n", + " \"design_type\": [\"Maxwell 3D\"],\n", + " \"fields_type\": [\"Fields\"],\n", + " \"primary_sweep\": \"Distance\",\n", + " \"assignment\": \"\",\n", + " \"assignment_type\": [\"Line\"],\n", + " \"operations\": [\n", + " \"NameOfExpression('')\",\n", + " \"Operation('ScalarZ')\",\n", + " \"Scalar_Constant(1000)\",\n", + " \"Operation('*')\",\n", + " \"Operation('Smooth')\",\n", + " ],\n", + " \"report\": [\"Field_3D\"],\n", + "}\n", + "m3d.post.fields_calculator.add_expression(bz, None)" + ] + }, + { + "cell_type": "markdown", + "id": "a04956d6", + "metadata": {}, + "source": [ + "## Plot mag(Bz) as a function of frequency\n", + "\n", + "Plot mag(Bz) as a function of frequency for both coil positions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7791086", + "metadata": {}, + "outputs": [], + "source": [ + "variations = {\n", + " \"Distance\": [\"All\"],\n", + " \"Freq\": [\"All\"],\n", + " \"Phase\": [\"0deg\"],\n", + " \"Coil_Position\": [\"All\"],\n", + "}\n", + "\n", + "m3d.post.create_report(\n", + " expressions=\"mag(Bz)\",\n", + " variations=variations,\n", + " primary_sweep_variable=\"Distance\",\n", + " report_category=\"Fields\",\n", + " context=\"Line_AB\",\n", + " plot_name=\"mag(Bz) Along 'Line_AB' Coil\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c9ef93fc", + "metadata": {}, + "source": [ + "## Get simulation results from a solved setup\n", + "\n", + "Get simulation results from a solved setup as a ``SolutionData`` object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89114871", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "solutions = m3d.post.get_solution_data(\n", + " expressions=\"mag(Bz)\",\n", + " report_category=\"Fields\",\n", + " context=\"Line_AB\",\n", + " variations=variations,\n", + " primary_sweep_variable=\"Distance\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b7f97ea3", + "metadata": {}, + "source": [ + "## Set up sweep value and plot solution" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ac6bdb8", + "metadata": {}, + "outputs": [], + "source": [ + "solutions.active_variation[\"Coil_Position\"] = -0.02\n", + "solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "c7d2551e", + "metadata": {}, + "source": [ + "## Change sweep value and plot solution\n", + "\n", + "Change the sweep value and plot the solution again.\n", + "Uncomment to show plots." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "792fc8aa", + "metadata": {}, + "outputs": [], + "source": [ + "solutions.active_variation[\"Coil_Position\"] = 0\n", + "# solutions.plot()" + ] + }, + { + "cell_type": "markdown", + "id": "2f399386", + "metadata": {}, + "source": [ + "## Plot induced current density on surface of ladder plate\n", + "\n", + "Plot the induced current density, ``\"Mag_J\"``, on the surface of the ladder plate." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3901cab8", + "metadata": {}, + "outputs": [], + "source": [ + "ladder_plate = m3d.modeler.objects_by_name[\"LadderPlate\"]\n", + "intrinsics = {\"Freq\": \"50Hz\", \"Phase\": \"0deg\"}\n", + "m3d.post.create_fieldplot_surface(\n", + " assignment=ladder_plate.faces,\n", + " quantity=\"Mag_J\",\n", + " intrinsics=intrinsics,\n", + " plot_name=\"Mag_J\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9a7dc0ca", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ff40e76", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "56bc8db2", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3050d8d9", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/examples/low_frequency/team_problem/index.rst.txt b/version/dev/_sources/examples/low_frequency/team_problem/index.rst.txt new file mode 100644 index 00000000..c7a9a0be --- /dev/null +++ b/version/dev/_sources/examples/low_frequency/team_problem/index.rst.txt @@ -0,0 +1,39 @@ +T.E.A.M. +~~~~~~~~ + +These examples use PyAEDT to show some T.E.A.M. applications. + +.. grid:: 2 + + .. grid-item-card:: Asymmetric conductor analysis + :padding: 2 2 2 2 + :link: asymmetric_conductor + :link-type: doc + + .. image:: _static/asymmetric_conductor.png + :alt: Asymmetric conductor + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up the TEAM 7 problem for an asymmetric conductor with a hole and solve it using the Maxwell 3D eddy current solver. + + .. grid-item-card:: Bath plate analysis + :padding: 2 2 2 2 + :link: bath_plate + :link-type: doc + + .. image:: _static/bath.png + :alt: Bath + :width: 250px + :height: 200px + :align: center + + This example uses PyAEDT to set up the TEAM 3 bath plate problem and solve it using the Maxwell 3D eddy current solver. + + + .. toctree:: + :hidden: + + asymmetric_conductor + bath_plate diff --git a/version/dev/_sources/examples/template.ipynb.txt b/version/dev/_sources/examples/template.ipynb.txt new file mode 100644 index 00000000..b1f76036 --- /dev/null +++ b/version/dev/_sources/examples/template.ipynb.txt @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6131d585", + "metadata": {}, + "source": [ + "# Short, Descriptive Title (do not specify the application name here, i.e.: Maxwell2D, Maxwell3D etc)\n", + "\n", + "Description:\n", + "\n", + "Most examples can be described as a series of steps that comprise a workflow.\n", + "1. Import packages and instantiate the application.\n", + "2. Do something useful and interesting.\n", + "3. View the results.\n", + "\n", + "Keywords: **Template**, **Jupyter**" + ] + }, + { + "cell_type": "markdown", + "id": "7cf1a831", + "metadata": {}, + "source": [ + "## Perform imports and define constants\n", + "\n", + "Perform required imports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5b42a09", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import tempfile\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69260400", + "metadata": {}, + "outputs": [], + "source": [ + "import ansys.aedt.core" + ] + }, + { + "cell_type": "markdown", + "id": "3aaf2b49", + "metadata": {}, + "source": [ + "Define constants." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "078cd64e", + "metadata": {}, + "outputs": [], + "source": [ + "AEDT_VERSION = \"2024.2\"\n", + "NUM_CORES = 4\n", + "NG_MODE = False # Open AEDT UI when it is launched." + ] + }, + { + "cell_type": "markdown", + "id": "d219117d", + "metadata": {}, + "source": [ + "## Create temporary directory\n", + "\n", + "Create a temporary directory where downloaded data or\n", + "dumped data can be stored.\n", + "If you'd like to retrieve the project data for subsequent use,\n", + "the temporary folder name is given by ``temp_folder.name``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "201239b6", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" + ] + }, + { + "cell_type": "markdown", + "id": "953a6757", + "metadata": {}, + "source": [ + "## Launch AEDT and application\n", + "\n", + "Create an instance of the application (such as ``Maxwell3d`` or``Hfss``)\n", + "with a class (such as ``m3d`` or``hfss``) by providing\n", + "the project and design names, the solver, and the version." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6831f81", + "metadata": {}, + "outputs": [], + "source": [ + "project_name = os.path.join(temp_folder.name, \"my_project.aedt\")\n", + "m3d = ansys.aedt.core.Maxwell3d(\n", + " project=project_name,\n", + " design=\"my_design\",\n", + " solution_type=\"my_solver\",\n", + " version=AEDT_VERSION,\n", + " non_graphical=NG_MODE,\n", + " new_desktop=True,\n", + ")\n", + "m3d.modeler.model_units = \"mm\"" + ] + }, + { + "cell_type": "markdown", + "id": "ca74c8fd", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Preprocess\n", + "\n", + "Description of preprocessing task.\n", + "Add as many sections as needed for preprocessing tasks." + ] + }, + { + "cell_type": "markdown", + "id": "0650ad92", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Postprocess\n", + "\n", + "Description of postprocessing task.\n", + "Add as many sections as needed for postprocessing tasks." + ] + }, + { + "cell_type": "markdown", + "id": "f15f1bee", + "metadata": {}, + "source": [ + "## Release AEDT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a785f02", + "metadata": {}, + "outputs": [], + "source": [ + "m3d.save_project()\n", + "m3d.release_desktop()\n", + "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", + "time.sleep(3)" + ] + }, + { + "cell_type": "markdown", + "id": "d8a964ab", + "metadata": {}, + "source": [ + "## Clean up\n", + "\n", + "All project files are saved in the folder ``temp_folder.name``.\n", + "If you've run this example as a Jupyter notebook, you\n", + "can retrieve those project files. The following cell\n", + "removes all temporary files, including the project folder." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b5362a7", + "metadata": {}, + "outputs": [], + "source": [ + "temp_folder.cleanup()" + ] + } + ], + "metadata": { + "jupytext": { + "cell_metadata_filter": "-all", + "main_language": "python", + "notebook_metadata_filter": "-all" + }, + "nbsphinx": { + "execute": "never" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/version/dev/_sources/index.rst.txt b/version/dev/_sources/index.rst.txt new file mode 100644 index 00000000..bb6fdd03 --- /dev/null +++ b/version/dev/_sources/index.rst.txt @@ -0,0 +1,96 @@ +Examples +======== + +**Useful links**: +`Installation `_ | +`Source repository `_ | +`Issues `_ + +This repository contains end-to-end embedding examples that demonstrate how to use +`PyAEDT `_. + + +.. grid:: 2 + + .. grid-item-card:: PyAEDT basics + :padding: 2 2 2 2 + :link: https://aedt.docs.pyansys.com/version/stable/User_guide/index.html + :link-type: url + + .. image:: examples/basic/_static/logo.png + :alt: PyAEDT logo + :width: 250px + :height: 200px + :align: center + + Links to brief tutorials provided in the PyAEDT documentation. + + .. grid-item-card:: Examples by AEDT application + :padding: 2 2 2 2 + :link: examples/aedt/index + :link-type: doc + + .. image:: examples/aedt/_static/aedt.png + :alt: AEDT + :width: 250px + :height: 200px + :align: center + + Provides examples organized by AEDT applications. + + .. grid-item-card:: High Frequency + :padding: 2 2 2 2 + :link: examples/high_frequency/index + :link-type: doc + + .. image:: examples/high_frequency/_static/hf.png + :alt: High frequency IC + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for high-frequency applications. + + .. grid-item-card:: Low Frequency + :padding: 2 2 2 2 + :link: examples/low_frequency/index + :link-type: doc + + .. image:: examples/low_frequency/_static/motor_maxwell.png + :alt: Low frequency motor + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for low-frequency applications. + + .. grid-item-card:: Electrothermal + :padding: 2 2 2 2 + :link: examples/electrothermal/index + :link-type: doc + + .. image:: examples/electrothermal/_static/icepak_logo.png + :alt: Icepak + :width: 250px + :height: 200px + :align: center + + Provides examples of PyAEDT capabilities for electrothermal applications. + + .. grid-item-card:: Pre-processing and post-processing + :padding: 2 2 2 2 + :link: examples/aedt_general/index + :link-type: doc + + .. image:: examples/aedt_general/_static/aedt_electronics.png + :alt: AEDT electronics + :width: 250px + :height: 200px + :align: center + + Provides examples of some general AEDT pre-processing and post-processing capabilities. + + .. toctree:: + :hidden: + + examples/index diff --git a/version/dev/_sphinx_design_static/design-tabs.js b/version/dev/_sphinx_design_static/design-tabs.js new file mode 100644 index 00000000..2952d2e2 --- /dev/null +++ b/version/dev/_sphinx_design_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/version/dev/_sphinx_design_static/sphinx-design.min.css b/version/dev/_sphinx_design_static/sphinx-design.min.css new file mode 100644 index 00000000..173af945 --- /dev/null +++ b/version/dev/_sphinx_design_static/sphinx-design.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative;font-size:var(--sd-fontsize-dropdown)}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary.sd-summary-title{padding:.5em .6em .5em 1em;font-size:var(--sd-fontsize-dropdown-title);font-weight:var(--sd-fontweight-dropdown-title);user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;list-style:none;display:inline-flex;justify-content:space-between}details.sd-dropdown summary.sd-summary-title::-webkit-details-marker{display:none}details.sd-dropdown summary.sd-summary-title:focus{outline:none}details.sd-dropdown summary.sd-summary-title .sd-summary-icon{margin-right:.6em;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary.sd-summary-title .sd-summary-text{flex-grow:1;line-height:1.5;padding-right:.5rem}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker{pointer-events:none;display:inline-flex;align-items:center}details.sd-dropdown summary.sd-summary-title .sd-summary-state-marker svg{opacity:.6}details.sd-dropdown summary.sd-summary-title:hover .sd-summary-state-marker svg{opacity:1;transform:scale(1.1)}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown .sd-summary-chevron-right{transition:.25s}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-right{transform:rotate(90deg)}details.sd-dropdown[open]>.sd-summary-title .sd-summary-chevron-down{transform:rotate(180deg)}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-bg: rgba(0, 113, 188, 0.2);--sd-color-secondary-bg: rgba(108, 117, 125, 0.2);--sd-color-success-bg: rgba(40, 167, 69, 0.2);--sd-color-info-bg: rgba(23, 162, 184, 0.2);--sd-color-warning-bg: rgba(240, 179, 126, 0.2);--sd-color-danger-bg: rgba(220, 53, 69, 0.2);--sd-color-light-bg: rgba(248, 249, 250, 0.2);--sd-color-muted-bg: rgba(108, 117, 125, 0.2);--sd-color-dark-bg: rgba(33, 37, 41, 0.2);--sd-color-black-bg: rgba(0, 0, 0, 0.2);--sd-color-white-bg: rgba(255, 255, 255, 0.2);--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem;--sd-fontsize-dropdown: inherit;--sd-fontsize-dropdown-title: 1rem;--sd-fontweight-dropdown-title: 700} diff --git a/version/dev/_static/404.rst b/version/dev/_static/404.rst new file mode 100644 index 00000000..c5599198 --- /dev/null +++ b/version/dev/_static/404.rst @@ -0,0 +1,6 @@ +Oops! +===== + +This is unexpected. The page you are requesting does not exist. + +If this page should exist, please contact `{{ theme_contact_mail }} <{{ theme_contact_mail }}>`_. \ No newline at end of file diff --git a/version/dev/_static/CSV_Import.png b/version/dev/_static/CSV_Import.png new file mode 100644 index 00000000..b73cd592 Binary files /dev/null and b/version/dev/_static/CSV_Import.png differ diff --git a/version/dev/_static/MCAD.PNG b/version/dev/_static/MCAD.PNG new file mode 100644 index 00000000..5762d0e3 Binary files /dev/null and b/version/dev/_static/MCAD.PNG differ diff --git a/version/dev/_static/README.md b/version/dev/_static/README.md new file mode 100644 index 00000000..708bf655 --- /dev/null +++ b/version/dev/_static/README.md @@ -0,0 +1,6 @@ +### _static + +Place custom CSS files in this folder. + +Emphasis should be on improving the ``ansys-sphinx-theme`` and +having a unified "feel" across the PyAnsys packages. diff --git a/version/dev/_static/ansys-favicon.png b/version/dev/_static/ansys-favicon.png new file mode 100644 index 00000000..cfb2e535 Binary files /dev/null and b/version/dev/_static/ansys-favicon.png differ diff --git a/version/dev/_static/ansys_logo_transparent_black.png b/version/dev/_static/ansys_logo_transparent_black.png new file mode 100644 index 00000000..8ce219af Binary files /dev/null and b/version/dev/_static/ansys_logo_transparent_black.png differ diff --git a/version/dev/_static/ansys_logo_transparent_white.png b/version/dev/_static/ansys_logo_transparent_white.png new file mode 100644 index 00000000..6121882b Binary files /dev/null and b/version/dev/_static/ansys_logo_transparent_white.png differ diff --git a/version/dev/_static/assets/index_api.png b/version/dev/_static/assets/index_api.png new file mode 100644 index 00000000..1c4513d3 Binary files /dev/null and b/version/dev/_static/assets/index_api.png differ diff --git a/version/dev/_static/assets/index_api.svg b/version/dev/_static/assets/index_api.svg new file mode 100644 index 00000000..69cedeee --- /dev/null +++ b/version/dev/_static/assets/index_api.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/version/dev/_static/assets/index_contribute.png b/version/dev/_static/assets/index_contribute.png new file mode 100644 index 00000000..b839bf0a Binary files /dev/null and b/version/dev/_static/assets/index_contribute.png differ diff --git a/version/dev/_static/assets/index_contribute.svg b/version/dev/_static/assets/index_contribute.svg new file mode 100644 index 00000000..3ac50a45 --- /dev/null +++ b/version/dev/_static/assets/index_contribute.svg @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/version/dev/_static/assets/index_examples.png b/version/dev/_static/assets/index_examples.png new file mode 100644 index 00000000..0cae884b Binary files /dev/null and b/version/dev/_static/assets/index_examples.png differ diff --git a/version/dev/_static/assets/index_examples.svg b/version/dev/_static/assets/index_examples.svg new file mode 100644 index 00000000..adfb734e --- /dev/null +++ b/version/dev/_static/assets/index_examples.svg @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/version/dev/_static/assets/index_getting_started.png b/version/dev/_static/assets/index_getting_started.png new file mode 100644 index 00000000..fdf713e0 Binary files /dev/null and b/version/dev/_static/assets/index_getting_started.png differ diff --git a/version/dev/_static/assets/index_getting_started.svg b/version/dev/_static/assets/index_getting_started.svg new file mode 100644 index 00000000..0c8b8aca --- /dev/null +++ b/version/dev/_static/assets/index_getting_started.svg @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/version/dev/_static/assets/index_user_guide.png b/version/dev/_static/assets/index_user_guide.png new file mode 100644 index 00000000..d27305b8 Binary files /dev/null and b/version/dev/_static/assets/index_user_guide.png differ diff --git a/version/dev/_static/assets/index_user_guide.svg b/version/dev/_static/assets/index_user_guide.svg new file mode 100644 index 00000000..40366890 --- /dev/null +++ b/version/dev/_static/assets/index_user_guide.svg @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/version/dev/_static/basic.css b/version/dev/_static/basic.css new file mode 100644 index 00000000..4c6d6e29 --- /dev/null +++ b/version/dev/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 270px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/version/dev/_static/bdf.png b/version/dev/_static/bdf.png new file mode 100644 index 00000000..ad9a532a Binary files /dev/null and b/version/dev/_static/bdf.png differ diff --git a/version/dev/_static/check-solid.svg b/version/dev/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/version/dev/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/version/dev/_static/clipboard.min.js b/version/dev/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/version/dev/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/version/dev/_static/copybutton.css b/version/dev/_static/copybutton.css new file mode 100644 index 00000000..f1916ec7 --- /dev/null +++ b/version/dev/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/version/dev/_static/copybutton.js b/version/dev/_static/copybutton.js new file mode 100644 index 00000000..32f83eab --- /dev/null +++ b/version/dev/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '>>> ?|\\.\\.\\. ', true, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/version/dev/_static/copybutton_funcs.js b/version/dev/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/version/dev/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/version/dev/_static/css/ansys-sphinx-theme-variable.css b/version/dev/_static/css/ansys-sphinx-theme-variable.css new file mode 100644 index 00000000..71f301bc --- /dev/null +++ b/version/dev/_static/css/ansys-sphinx-theme-variable.css @@ -0,0 +1,400 @@ +/*Contains variables for colors and fonts used in the theme*/ +@import url("https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&family=Open+Sans:ital,wght@0,400;0,600;1,400;1,600&display=swap"); + +@font-face { + font-family: "Source Sans Pro Light"; + src: url(../fonts/SourceSansPro-Light.ttf); +} + +@font-face { + font-family: "Source Sans Pro"; + src: url(../fonts/SourceSansPro-Regular.ttf); +} + +:root { + /** Ansys specific changes to the theme */ + + /** + * Ansys Font family + * + * These are adapted from https://systemfontstack.com/ + */ + --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI, + "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, + Segoe UI Symbol; + --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco, + Liberation Mono, Lucida Console, monospace; + + --pst-font-family-base: "Source Sans Pro", sans-serif, + var(--pst-font-family-base-system); + --pst-font-family-heading: "Source Sans Pro", sans-serif, + var(--pst-font-family-base-system); + --pst-font-family-monospace: monospace, Courier, + var(--pst-font-family-monospace-system); + + /** + * Ansys compatible colors + * + * Colors are defined in rgb string way, "red, green, blue" + */ + --ansysGold: rgb(255, 183, 27); /* #FFB71B */ + --ansysBronze: rgb(200, 146, 17); /* #C89211 */ + --pythonBlue: rgb(57, 114, 161); /* #3972a1 */ + --pst-font-size-h1: 36px; + --pst-font-size-h2: 32px; + --pst-font-size-h3: 28px; + --pst-font-size-h4: 20px; + --pst-font-size-h5: 14px; + --pst-font-size-h6: 11px; + --ast-global-line-height: 24px; + --bs-nav-link-font-size: 14px; + --bs-navbar-color: var(--bs-ast-navbar-color); + --ast-font-sidebar-header: var(--pst-font-size-h5); + /** + * table font sizes + */ + --pst-table-font-size: 14px; + --pst-table-header-font-size: 12px; + + /** + * sphinx design font sizes + */ + + --ast-sphinx-design-font-size: 14px; + --ast-sphinx-design-font-family: "Open Sans", sans-serif; + --ast-sphinx-design-border-radius: 4px; + + /** +* admonitions +*/ + --ast-admonitions-font-size: 14px; + --ast-admonitions-padding: 8px 16px; + --ast-admonitions-border-radius: 8px; + --ast-admonitions-icon-size: 15px; + --ast-admonition-icon-height: 24px; + --ast-admonition-icon-width: 24px; + --ast-admonition-icon-margin-left: 8px; +} + +html[data-theme="light"] { + /** + * main colors + */ + --ast-color-text: #353535; + --ast-color-active-text: #353535; + --ast-color-hover-text: #353535; + --pst-color-background: #f7f7f7; + --pst-color-primary: #353535; + --pst-color-secondary: #f2f2f2; + --pst-color-success: rgb(40, 167, 69); + --pst-color-text-base: rgb(0, 0, 0); + --pst-color-text-muted: #353535; + --pst-color-border: #686868; + --pst-color-shadow: rgb(216, 216, 216); + --pst-color-info: var(--pst-color-link); + --pst-color-link-hover: #686868; + + /** + * Navigation colors + */ + --pst-color-on-background: var( + --pst-color-background + ); /* important tag from pydata-sphinx-theme */ + --ast-navbar-color: #686868; + --ast-navbar-hover-color: var(--ast-color-hover-text); + --ast-navbar-active-color: var(--ast-color-active-text); + --ast-navbar-active-border-color: #000000; + --ast-ring-shadow-focused: 0px 0px 0px 2px #ffffff, 0px 0px 0px 4px #1a78c2; + + /** + * sidebar colors + */ + --ast-sidebar-primary-text: var(--ast-color-text); + --ast-sidebar-hover-background: #ececec; + --ast-sidebar-active-background: #d9d9d9; + + /** + * depth colors + */ + /* --pst-color-on-background: rgb(0, 0, 0); */ + --pst-color-on-surface: #f2f2f2; + + /** + * table + */ + --ast-color-table-background: #ffffff; + --ast-color-enabled-table-text: var(--ast-color-text); + --ast-color-table-row-hover-bg: #ececec; + --ast-color-table-active-bg: #e9f4fe; + --ast-color-table-header-text: #686868; + --ast-color-table-cell-text: var(--ast-color-text); + --ast-table-outer-border: #ececec; + --ast-color-table-inner-border: #ececec; + + --pst-color-panel-background: var(--pst-color-on-background); + + /** + * layout + */ + + --ast-color-link: #1e6ddc; + --ast-color-link-hover: #1856af; + --ast-color-link-active: #104188; + --ast-color-link-visited: #9a33cb; + --ast-color-link-visited-hover: #7f29a2; + --ast-color-inline-code: var( + --pst-color-text-muted + ); /* inline code color for docutils (_base.scss)*/ + --pst-color-target: rgb(255, 255, 255); + + /** + * color for sphinx-gallery-code output + */ + --pst-color-codecell: #fafae2; + --pst-color-codeout: var(--pst-color-inline-code); + --pst-color-sig: #0965c8; + --pst-color-code-s1: #b35000; + --pst-color-code-c1: #095d0a; + + --ast-sphinx-gallery-download-background: #1a1a1a; + --ast-sphinx-gallery-download-background-hover: #353535; + --ast-sphinx-gallery-download-text: #fdfdfd; + + /** + * sphinx design + */ + --sd-color-primary: var(--pst-color-text-base); + --ast-color-enable-card-background: #ffffff; + --ast-color-enable-border: #d9d9d9; + --ast-color-hover-card-background: #ececec; + --ast-dropdown-border-color: #d9d9d9; + --ast-dropdown-border-color-hover: #8e8e8e; + + --ast-color-sphinx-design-primary: #353535; + --ast-color-sphinx-design-background: #ffffff; + --sd-color-primary: #141414; + --sd-color-primary-highlight: var(--ast-color-sphinx-design-primary); + --sd-color-primary-text: var(--ast-color-sphinx-design-background); + --sd-color-secondary: var(--ast-color-sphinx-design-background); + --sd-color-secondary-text: #141414; + --sd-color-secondary-highlight: var(--ast-color-hover-card-background); + --sd-color-secondary-bg: var(--ast-color-sphinx-design-background); + --ast-sd-bg-secondary-hover: var(--ast-color-hover-card-background); + --ast-background-tab-focus: #d9d9d9; + --ast-background-tab-hover: #ececec; + --ast-tab-border-color: #d9d9d9; + --ast-tab-border-color-hover: #8e8e8e; + --ast-tab-border-color-active: #000000; + --ast-dropdown-text-color: #686868; + --ast-box-shadow-active: 0px 1px 2px 0px rgba(0, 0, 0, 0.08), + 0px 2px 4px 0px rgba(0, 0, 0, 0.12); + --ast-box-shadow-hover: 0px 1px 2px 0px rgba(0, 0, 0, 0.08), + 0px 4px 8px 2px rgba(0, 0, 0, 0.12); + /** + * search hide match + */ + --pst-color-search-match: #91969b; + + /** + * admonitions + */ + --ast-admonition-neutral-icon: #353535; + --ast-admonition-neutral-border: #686868; + --ast-admonition-info-icon: #1a78c2; + --ast-admonition-info-border: #1a78c2; + --ast-admonition-success-icon: #006600; + --ast-admonition-success-border: #008000; + --ast-admonition-warning-icon: #caad2a; + --ast-admonition-warning-border: #fdd835; + --ast-admonition-danger-icon: #b72e2a; + --ast-admonition-danger-border: #e53935; + --ast-admonitions-color: var(--ast-color-text); + + /** + * search bars + */ + --ast-search-bar-enable-background: #ffffff; + --ast-search-bar-enable-border: #d9d9d9; + --ast-search-bar-enable-text: #686868; + --ast-suggestion-header-background: #d9d9d9; + --ast-catagory-header-text: #353535; + --ast-catagory-suggestion-text: #8e8e8e; + --ast-suggestion-text-color: #000000; + + /** + * dropdown header + */ + --ast-dropdown-header-border: #d9d9d9; +} + +html[data-theme="dark"] { + /** + * main colors + */ + --ast-color-text: #ececec; + --ast-color-active-text: #d5d5d5; + --ast-color-hover-text: #d5d5d5; + --pst-color-primary: #ececec; + --pst-color-secondary: #353535; + --pst-color-success: rgb(72, 135, 87); + --pst-color-text-base: rgb(201, 209, 217); + --pst-color-text-muted: rgb(192, 192, 192); + --pst-color-border: rgb(192, 192, 192); + --pst-color-shadow: rgb(104, 102, 102); + --pst-color-background: #1a1a1a; + --pst-color-surface: rgb(41, 41, 41); + --pst-color-on-surface: rgb(55, 55, 55); + --pst-color-info: var(--pst-color-secondary); + --pst-color-link-hover: #b3b3b3; + + /** + * extensions + */ + + --pst-color-panel-background: var(--pst-color-on-background); + + /** + * Navigation colors + */ + + --pst-color-on-background: var( + --pst-color-background + ); /* important tag from pydata-sphinx-theme */ + --ast-navbar-color: #8e8e8e; + --ast-navbar-hover-color: var(--ast-color-hover-text); + --ast-navbar-active-color: var(--ast-color-active-text); + --ast-navbar-active-border-color: #ffffff; + --ast-nav-link-color: var(--ast-navbar-color); + --ast-ring-shadow-focused: 0px 0px 0px 2px #282828, 0px 0px 0px 4px #4dabf5; + + /** + * sidebar colors + */ + --ast-sidebar-primary-text: var(--ast-color-text); + --ast-sidebar-hover-background: #3d3d3d; + --ast-sidebar-active-background: #2d2d2d; + --ast-color-inline-code: var( + --pst-color-text-muted + ); /* inline code color for docutils (_base.scss)*/ + + /** + * layout + */ + + --ast-color-link: #1e6ddc; + --ast-color-link-hover: #1856af; + --ast-color-link-active: #579ce5; + --ast-color-link-visited: #c58ac5; + --ast-color-link-visited-hover: #a96ba9; + --pst-color-target: rgb(71, 39, 0); + + /** + * color for sphinx-gallery-code output + */ + --pst-color-codecell: #353535; + --pst-color-codeout: #f2f4f6; + --pst-color-sig: #d6ab1e; + --pst-color-code-s1: #d79a60; + --pst-color-code-c1: #8fb842; + + --ast-sphinx-gallery-download-background: #ffffff; + --ast-sphinx-gallery-download-background-hover: #ececec; + --ast-sphinx-gallery-download-text: #1a1a1a; + + /** + * table hovering + */ + --ast-color-table-background: #353535; + --ast-color-enabled-table-text: #ececec; + --ast-color-table-row-hover-bg: #3d3d3d; + --ast-color-table-header-text: #d3d3d3; + --ast-color-table-cell-text: #ececec; + --ast-color-table-active-bg: #3d3d3d; + --ast-table-outer-border: #d3d3d3; + --ast-color-table-inner-border: #d3d3d3; + + /** + * search hide match + */ + --pst-color-search-match: var(--pst-color-primary); + + /** + * sphinx design + */ + + --sd-color-primary: var(--pst-color-text-base); + --ast-color-enable-card-background: #282828; + --ast-color-enable-border: #e5e5e5; + --ast-color-hover-card-background: #3d3d3d; + --ast-dropdown-border-color: #3d3d3d; + --ast-dropdown-border-color-hover: #8e8e8e; + + --ast-color-sphinx-design-primary: #ececec; + --ast-color-sphinx-design-background: #282828; + --sd-color-primary: #d5d5d5; + --sd-color-primary-highlight: var(--ast-color-sphinx-design-primary); + --sd-color-primary-text: var(--ast-color-sphinx-design-background); + --sd-color-secondary: var(--ast-color-sphinx-design-background); + --sd-color-secondary-text: #d5d5d5; + --sd-color-secondary-highlight: var(--ast-color-hover-card-background); + --sd-color-secondary-bg: var(--ast-color-sphinx-design-background); + --ast-sd-bg-secondary-hover: var(--ast-color-hover-card-background); + --ast-background-tab-focus: #2d2d2d; + --ast-background-tab-hover: #3d3d3d; + --ast-tab-border-color: #e5e5e5; + --ast-tab-border-color-hover: #8e8e8e; + --ast-tab-border-color-active: #ffffff; + --ast-dropdown-text-color: #e5e5e5; + --ast-box-shadow-active: 0px 1px 2px 0px rgba(0, 0, 0, 0.4), + 0px 2px 4px 0px rgba(0, 0, 0, 0.48); + --ast-box-shadow-hover: 0px 1px 2px 0px rgba(0, 0, 0, 0.4), + 0px 4px 8px 2px rgba(0, 0, 0, 0.48); + + /** +* admonitions +*/ + --ast-admonition-neutral-icon: #ececec; + --ast-admonition-neutral-border: #8e8e8e; + --ast-admonition-info-icon: #1a78c2; + --ast-admonition-info-border: #1856af; + --ast-admonition-success-icon: #006600; + --ast-admonition-success-border: #147914; + --ast-admonition-warning-icon: #caad2a; + --ast-admonition-warning-border: #bba12e; + --ast-admonition-danger-icon: #b72e2a; + --ast-admonition-danger-border: #b12422; + --ast-admonitions-color: var(--ast-color-text); + + /** + * search bars + */ + --ast-search-bar-enable-background: #2d2d2d; + --ast-search-bar-enable-border: #3d3d3d; + --ast-search-bar-enable-text: #d3d3d3; + --ast-suggestion-header-background: #3d3d3d; + --ast-catagory-header-text: #ececec; + --ast-catagory-suggestion-text: #686868; + --ast-suggestion-text-color: #ffffff; + + /** + * dropdown header + */ + --ast-dropdown-header-border: #3d3d3d; +} + +/** +* font sizes +* body and content +*/ + +body { + font-family: "Open Sans", sans-serif; + line-height: var(--ast-global-line-height); + font-size: 14px; + color: var(--ast-color-text); +} + +h1, +h2 { + color: var(--pst-color-text-base); +} diff --git a/version/dev/_static/css/ansys_sphinx_theme.css b/version/dev/_static/css/ansys_sphinx_theme.css new file mode 100644 index 00000000..54acbf81 --- /dev/null +++ b/version/dev/_static/css/ansys_sphinx_theme.css @@ -0,0 +1,45 @@ +/* Provided by the Sphinx base theme template at build time */ + +@import "../basic.css"; +@import "../sg_gallery.css"; +@import "ansys-sphinx-theme-variables.css"; +@import "pydata-sphinx-theme-custom.css"; +@import "breadcrumbs.css"; +@import "meilisearch.css"; +@import "sphinx-design.css"; +@import "table-custom.css"; +@import "sphinx-gallery.css"; + +/* +* Code cell +*/ +.xref.std.std-ref { + color: var(--pst-color-inline-code); + font-family: "Inconsolata"; + font-weight: normal; + font-style: italic; + padding: 0.1rem 0.25rem; + padding-top: 0.1rem; + padding-right: 0.25rem; + padding-bottom: 0.1rem; + padding-left: 0.25rem; + font-size: 90%; + background-color: var(--pst-color-on-surface); + border: 1px solid var(--pst-color-border); + border-radius: 0.25rem; +} + +/* Reduce empty-space around Notes and Examples headings */ +p.rubric { + margin-top: 0.75em; + margin-bottom: 0.75em; +} + +/* +* Autosummary +*/ + +.autosummary tr:nth-child(odd), +.autosummary tr:nth-child(even) { + background-color: var(--pst-color-background); +} diff --git a/version/dev/_static/css/breadcrumbs.css b/version/dev/_static/css/breadcrumbs.css new file mode 100644 index 00000000..19c3eab0 --- /dev/null +++ b/version/dev/_static/css/breadcrumbs.css @@ -0,0 +1,110 @@ +/* Provided by the Sphinx base theme template at build time, +styles exclusively for the ansys-sphinx-theme classes. */ + +@import "ansys-sphinx-theme-variable.css"; + +/** +* Breadcrumbs +*/ + +ul.bd-breadcrumbs li.breadcrumb-item { + padding: 0px; + font-size: 12px; + display: flex; +} + +ul.bd-breadcrumbs li.breadcrumb-item:hover { + text-decoration: underline; + font-size: 12px; +} + +ul.bd-breadcrumbs li.breadcrumb-item a { + color: var(--ast-navbar-color); + font-size: 12px; +} + +ul.bd-breadcrumbs li.breadcrumb-item a:hover { + text-decoration: underline; +} + +ul.bd-breadcrumbs li.breadcrumb-item a:active { + color: var(--ast-color-text); +} + +.breadcrumb-item.active { + color: var(--ast-color-text); +} + +/** +* Version warning announcement +*/ + +#announcement_msg { + display: flex; + justify-content: center; + position: relative; + width: 100%; + padding: 0.5rem 12.5%; + text-align: center; +} + +#announcement_msg :after { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + background-color: rgb(223, 95, 114); + opacity: 0.2; + content: ""; + z-index: -1; +} + +#announcement_msg :empty { + display: none; +} + +#announcement_msg p { + font-weight: bold; + margin: auto; + color: black; +} + +html[data-theme="dark"] #announcement_msg :after { + background-color: lightpink; + opacity: 0.5; +} + +#announcement_msg a { + color: #1e6ddc; +} + +.sidebar-cheatsheets { + text-align: center; +} + +.sidebar-cheatsheets h4 { + font-weight: var(--pst-sidebar-header-font-weight) !important; + font-size: var(--pst-sidebar-header-font-size) !important; + margin-bottom: 0.5rem; +} + +.sidebar-cheatsheets a { + display: inline-flex; + border: 0.5px solid var(--pst-color-border); + padding: 0.25rem; + max-width: 80%; +} + +.sidebar-cheatsheets a:hover { + background-color: var(--pst-color-border); + color: var(--pst-color-text-base); +} + +.sidebar-cheatsheets img { + padding: 0rem; +} + +.bd-sidebar-primary { + padding: 0.5rem; +} diff --git a/version/dev/_static/css/custom.css b/version/dev/_static/css/custom.css new file mode 100644 index 00000000..9ce55e58 --- /dev/null +++ b/version/dev/_static/css/custom.css @@ -0,0 +1,41 @@ +@import "../ansys-sphinx-theme.css"; + +.col-md-3 { + flex: 0 0 30%; + max-width: 30%; +} +.col-xl-7 { + flex: 0 0 53.33333%; + max-width: 53.33333%; + } + +.bd-toc { + padding-top: 5em; +} + + +nav.bd-links ul li.toctree-l1 > a { + font-size: .90rem; +} + +nav.bd-links ul li.toctree-l2 > a { + font-size: .85rem; + text-indent: 1px; +} +nav.bd-links ul li.toctree-l3 > a { + font-size: .85rem; + text-indent: 2px; +} + +nav.bd-links ul li.toctree-l4 > a { + font-size: .8rem; + text-indent: 3px; +} + +div.cell_output { + text-align: left !important; +} + +div.nbinput.container div.input_area, div.nboutput.container div.output_area { + display: block; +} diff --git a/version/dev/_static/css/highlight.css b/version/dev/_static/css/highlight.css new file mode 100644 index 00000000..6d41658d --- /dev/null +++ b/version/dev/_static/css/highlight.css @@ -0,0 +1,83 @@ +/* + * The 'friendly' style from Pygments CSS style. Directly taken from: + * https://github.com/richleland/pygments-css + * License is 'UNLICENSE.txt'. + */ + +@import "../../ansys-sphinx-theme.css"; + +/* Do not show number cells */ +.nbinput .prompt, +.nboutput .prompt { + display: none; +} + +.highlight .hll { background-color: #ffffcc !important; } +.highlight { font-size: 1rem; background: #f0f0f0 !important; } +.highlight .c { color: #60a0b0 !important; font-style: italic !important; } /* Comment */ +.highlight .err { border: 1px solid #FF0000 !important; } /* Error */ +.highlight .k { color: #007020 !important; font-weight: bold !important; } /* Keyword */ +.highlight .o { color: #666666 !important; } /* Operator */ +.highlight .ch { color: #60a0b0 !important; font-style: italic !important; } /* Comment.Hashbang */ +.highlight .cm { color: #60a0b0 !important; font-style: italic !important; } /* Comment.Multiline */ +.highlight .cp { color: #007020 !important; } /* Comment.Preproc */ +.highlight .cpf { color: #60a0b0 !important; font-style: italic !important; } /* Comment.PreprocFile */ +.highlight .c1 { color: #60a0b0 !important; font-style: italic !important; } /* Comment.Single */ +.highlight .cs { color: #60a0b0 !important; background-color: #fff0f0 !important; } /* Comment.Special */ +.highlight .gd { color: #A00000 !important; } /* Generic.Deleted */ +.highlight .ge { font-style: italic !important; } /* Generic.Emph */ +.highlight .gr { color: #FF0000 !important; } /* Generic.Error */ +.highlight .gh { color: #000080 !important; font-weight: bold !important; } /* Generic.Heading */ +.highlight .gi { color: #00A000 !important; } /* Generic.Inserted */ +.highlight .go { color: #888888 !important; } /* Generic.Output */ +.highlight .gp { color: #c65d09 !important; font-weight: bold !important; } /* Generic.Prompt */ +.highlight .gs { font-weight: bold !important; } /* Generic.Strong */ +.highlight .gu { color: #800080 !important; font-weight: bold !important; } /* Generic.Subheading */ +.highlight .gt { color: #0044DD !important; } /* Generic.Traceback */ +.highlight .kc { color: #007020 !important; font-weight: bold !important; } /* Keyword.Constant */ +.highlight .kd { color: #007020 !important; font-weight: bold !important; } /* Keyword.Declaration */ +.highlight .kn { color: #007020 !important; font-weight: bold !important; } /* Keyword.Namespace */ +.highlight .kp { color: #007020 !important; } /* Keyword.Pseudo */ +.highlight .kr { color: #007020 !important; font-weight: bold !important; } /* Keyword.Reserved */ +.highlight .kt { color: #902000 !important; } /* Keyword.Type */ +.highlight .m { color: #40a070 !important; } /* Literal.Number */ +.highlight .s { color: #4070a0 !important; } /* Literal.String */ +.highlight .na { color: #4070a0 !important; } /* Name.Attribute */ +.highlight .nb { color: #007020 !important; } /* Name.Builtin */ +.highlight .nc { color: #0e84b5 !important; font-weight: bold !important; } /* Name.Class */ +.highlight .no { color: #60add5 !important; } /* Name.Constant */ +.highlight .nd { color: #555555 !important; font-weight: bold !important; } /* Name.Decorator */ +.highlight .ni { color: #d55537 !important; font-weight: bold !important; } /* Name.Entity */ +.highlight .ne { color: #007020 !important; } /* Name.Exception */ +.highlight .nf { color: #06287e !important; } /* Name.Function */ +.highlight .nl { color: #002070 !important; font-weight: bold !important; } /* Name.Label */ +.highlight .nn { color: #0e84b5 !important; font-weight: bold !important; } /* Name.Namespace */ +.highlight .nt { color: #062873 !important; font-weight: bold !important; } /* Name.Tag */ +.highlight .nv { color: #bb60d5 !important; } /* Name.Variable */ +.highlight .ow { color: #007020 !important; font-weight: bold !important; } /* Operator.Word */ +.highlight .w { color: #bbbbbb !important; } /* Text.Whitespace */ +.highlight .mb { color: #40a070 !important; } /* Literal.Number.Bin */ +.highlight .mf { color: #40a070 !important; } /* Literal.Number.Float */ +.highlight .mh { color: #40a070 !important; } /* Literal.Number.Hex */ +.highlight .mi { color: #40a070 !important; } /* Literal.Number.Integer */ +.highlight .mo { color: #40a070 !important; } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 !important; } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 !important; } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 !important; } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 !important; } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0 !important; font-style: italic !important; } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 !important; } /* Literal.String.Double */ +.highlight .se { color: #4070a0 !important; font-weight: bold !important; } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 !important; } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0 !important; font-style: italic !important; } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 !important; } /* Literal.String.Other */ +.highlight .sr { color: #235388 !important; } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 !important; } /* Literal.String.Single */ +.highlight .ss { color: #517918 !important; } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 !important; } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e !important; } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 !important; } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 !important; } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 !important; } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 !important; } /* Name.Variable.Magic */ +.highlight .il { color: #40a070 !important; } /* Literal.Number.Integer.Long */ diff --git a/version/dev/_static/css/meilisearch.css b/version/dev/_static/css/meilisearch.css new file mode 100644 index 00000000..fdb6b118 --- /dev/null +++ b/version/dev/_static/css/meilisearch.css @@ -0,0 +1,205 @@ +@import "https://cdn.jsdelivr.net/npm/docs-searchbar.js@latest/dist/cdn/docs-searchbar.min.css"; +@import "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"; + +div[data-ds-theme] .searchbox { + overflow-y: scroll; + margin: auto; +} + +.docs-searchbar-suggestion--category-header { + background-color: var(--ast-suggestion-header-background); + border-radius: 4px; + text-align: left; + color: var(--ast-catagory-header-text) !important; + width: 680px; + padding: 4px; +} + +.dsb-suggestions { + width: 100%; + max-width: 140%; +} + +div[data-ds-theme] .meilisearch-autocomplete .dsb-dropdown-menu { + max-width: 1200px; + min-width: 800px; + width: 800px; +} +div[data-ds-theme] .meilisearch-autocomplete .docs-searchbar-suggestion { + width: 100%; +} + +div[data-ds-theme] .searchbox input { + height: 32px; + border-radius: 8px; + font-size: 18px; + font-family: "Open Sans", sans-serif; + box-shadow: 0px 0px 8px darkgrey; +} + +.docs-searchbar-footer { + display: none; +} + +.docs-searchbar-footer { + display: none; +} + +[class*="docs-searchbar-suggestion"] { + text-decoration: none; +} + +.docs-searchbar-suggestion--highlight { + box-shadow: none !important; +} + +div[data-ds-theme] .meilisearch-autocomplete { + text-align: center; + color: var(--pst-color-text-base); +} + +.form-control:focus, +.form-control:focus-visible, +.form-control { + background-color: var(--ast-search-bar-enable-background); + color: var(--ast-search-bar-enable-text); + font-size: 14px; + outline-color: var(--ast-search-bar-enable-border); + border: 0.5px solid var(--ast-search-bar-enable-border); + width: 670px; + max-width: 200%; + height: 40px; + margin-left: 5px; +} + +.search-button__wrapper.show input, +.search-button__wrapper.show svg { + font-size: 14px; +} + +.bd-search .search-button__kbd-shortcut { + background-color: var(--ast-search-bar-enable-background) !important; + box-shadow: none !important; + height: 40px; + display: flex; + flex-wrap: wrap; + align-content: center; +} + +.index-select { + color: var(--ast-search-bar-enable-text); + background: var(--ast-search-bar-enable-background); + height: 40px; + font-size: 14px; + font-family: "Open Sans", sans-serif; + border: 0.5px solid var(--ast-search-bar-enable-border); + border-radius: 4px; + box-shadow: none; + padding: 0px 8px; + margin-left: 2px; +} +:focus-visible { + outline: none; +} + +div[data-ds-theme] + .meilisearch-autocomplete + .dsb-dropdown-menu + [class^="dsb-dataset-"] { + position: relative; + border: 1px solid #d9d9d9; + background: var(--ast-search-bar-enable-background); + border-radius: 4px; + padding: 0 8px 8px; +} +div[data-ds-theme] .meilisearch-autocomplete .dsb-dropdown-menu { + max-height: 500px !important; + border: 1px solid #ccc; + left: -30px; + overflow-y: auto; +} + +div[data-ds-theme] .meilisearch-autocomplete .docs-searchbar-suggestion { + background: var(--ast-search-bar-enable-background); +} + +div[data-ds-theme] + .meilisearch-autocomplete + .docs-searchbar-suggestion--highlight { + color: var(--ast-suggestion-text-color) !important; + font-weight: 900; + background: transparent; + padding: 0 0.05em; +} + +.meilisearch-autocomplete .docs-searchbar-suggestion--text { + color: var(--ast-catagory-suggestion-text); + font-size: 12px; + line-height: var(--ast-global-line-height); +} + +div[data-ds-theme] + .meilisearch-autocomplete + .docs-searchbar-suggestion--subcategory-column { + width: None; + text-align: left; +} + +.meilisearch-autocomplete .docs-searchbar-suggestion--category-header { + width: 100%; + padding: 4px 8px; +} + +div[data-ds-theme] + .meilisearch-autocomplete + .docs-searchbar-suggestion--content { + display: block; +} + +div[data-ds-theme] .meilisearch-autocomplete .docs-searchbar-suggestion--title { + margin-bottom: 4px; + color: var(--ast-search-bar-enable-text); + font-size: 0.9em; + font-weight: 700; + width: 100%; +} + +/** +* Styling the scrollbar +*/ +div[data-ds-theme] + .meilisearch-autocomplete + .dsb-dropdown-menu::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; +} + +div[data-ds-theme] + .meilisearch-autocomplete + .dsb-dropdown-menu::-webkit-scrollbar-thumb { + background: var(--ast-search-bar-enable-background); + border-radius: inherit; +} + +div[data-ds-theme] + .meilisearch-autocomplete + .dsb-dropdown-menu::-webkit-scrollbar-track { + background: var(--ast-search-bar-enable-background); +} + +.bd-search { + gap: 8px; + background-color: var(--ast-search-bar-enable-background); + border: 0px solid var(--ast-search-bar-enable-border); + margin-bottom: 300px; +} +#search-icon { + font-size: 24px; + width: 24px; + height: 24px; + color: var(--ast-search-bar-enable-text); +} + +.form-control:focus { + box-shadow: none; +} diff --git a/version/dev/_static/css/pydata-sphinx-theme-custom.css b/version/dev/_static/css/pydata-sphinx-theme-custom.css new file mode 100644 index 00000000..f966e2ab --- /dev/null +++ b/version/dev/_static/css/pydata-sphinx-theme-custom.css @@ -0,0 +1,722 @@ +/* Changes associated with the Ansys Sphinx Theme */ +/* for pydata-sphinx-theme */ +@import "../styles/pydata-sphinx-theme.css"; +@import "ansys-sphinx-theme-variable.css"; + +/* +* +* _secondary sidebar and primary sidebars +* _sidebar-primary.scss +* +*/ +.bd-sidebar-primary, +.bd-sidebar-secondary { + max-height: calc(100vh - var(--pst-header-height) - 1vh); + line-height: var(--ast-global-line-height); + border: none; + overflow: hidden; +} + +.sidebar-secondary-item { + border: none; +} + +nav.bd-links p.bd-links__title, +nav.bd-links p.caption { + font-size: var(--ast-font-sidebar-header); + color: var(--ast-sidebar-primary-text); +} + +nav.bd-links li > a { + font-size: var(--ast-font-sidebar-header); + color: var(--ast-sidebar-primary-text); + text-decoration: none; + line-height: var(--ast-global-line-height); + padding: 4px 24px; +} + +nav.bd-links li > a:hover { + color: var(--ast-sidebar-primary-text); + background: var(--ast-sidebar-hover-background); + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: 4px; + text-decoration: none; +} + +nav.bd-links li > a.active, +nav.bd-links li > a.current { + color: var(--ast-color-text); + background: var(--ast-sidebar-active-background); + text-decoration: none; + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: 4px; + font-weight: bold; +} + +/** +* sidebar primary with children +*/ + +.bd-sidebar-primary li.has-children .caption, +.bd-sidebar-primary li.has-children > .reference { + padding: 4px 32px; +} + +nav.bd-links .current > a { + color: var(--ast-color-text); + background: var(--ast-sidebar-active-background); + text-decoration: none; + box-shadow: 1px 1px 2px 0px var(--ast-sidebar-active-background); + border-radius: 4px; + font-weight: bold; +} +/** +* secondary sidebar +* _toc-inpage.scss +*/ +.toc-entry a.nav-link { + color: var(--ast-sidebar-primary-text); + line-height: var(--ast-global-line-height); +} + +.toc-entry a.nav-link.active, +.toc-entry a.nav-link.current { + color: var(--ast-color-link); + text-decoration: none; + box-shadow: none; +} + +.toc-entry a.nav-link.active:hover, +.toc-entry a.nav-link.current:hover { + color: var(--ast-color-link-hover); + text-decoration: none; + box-shadow: none; + font-weight: bold; +} + +.toc-h2 { + font-size: 14px; + padding: 0.05em; +} + +.toc-h3 { + font-size: 14px; +} + +.toc-h4 { + font-size: 14px; +} + +.toc-entry a.nav-link:hover { + color: var(--ast-color-link-hover); + text-decoration: none; +} + +/** +* _base.scss related changes +*/ + +.editthispage a { + color: var(--pst-color-text-base); +} + +/** +* +* Dropdown button +* _header.scss +* +*/ + +.bd-header ul.navbar-nav > li.nav-item > .nav-link { + color: var(--ast-navbar-color); + font-weight: 600; +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:hover::before { + color: var(--ast-navbar-hover-color); + border-bottom: none; + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.08)); +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:hover { + color: var(--ast-navbar-hover-color); + border-color: var(--ast-navbar-hover-color); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.08)); +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:active { + color: var(--ast-navbar-active-color); + border-color: var(--ast-navbar-active-border-color); + border-width: 2px; + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.12)); +} + +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link::before, +.bd-header ul.navbar-nav > li.nav-item.current > .nav-link::after { + color: var(--ast-navbar-active-color); + border-bottom: 2px solid var(--ast-navbar-active-border-color); +} + +.bd-header ul.navbar-nav > li.nav-item > .nav-link:focus-visible { + color: var(--ast-navbar-color); + box-shadow: var(--ast-ring-shadow-focused); + outline: none; + outline-offset: 0px; +} + +html .pst-navbar-icon { + color: var(--ast-navbar-color); +} + +html .pst-navbar-icon:hover { + color: var(--ast-navbar-hover-color); + border-color: var(--ast-navbar-hover-color); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.08)); +} + +a.nav-link.pst-navbar-icon { + color: var(--ast-navbar-color); + font-weight: bold; +} + +a.nav-link.pst-navbar-icon:hover { + color: var(--ast-navbar-hover-color); + border-color: var(--ast-navbar-hover-color); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.08)); + font-weight: bold; +} + +a.nav-link.pst-navbar-icon:active { + color: var(--ast-navbar-active-color); + border-color: var(--ast-navbar-active-border-color); + font-weight: bold; +} + +ul.navbar-icon-links { + column-gap: 10px; +} + +.bd-header .navbar-header-items__center, +.bd-header .navbar-header-items__end { + column-gap: 10px; +} + +/* +* dropdown button after 5 sections +*/ + +.dropdown-item:hover { + font-weight: bold; + background-color: transparent; +} + +/** +* _search.scss +* Search bar +*/ + +.search-button-field { + border-color: var(--ast-navbar-active-border-color); + font-size: var(--ast-nav-link-font-size); + background-color: transparent; + color: var(--ast-navbar-color); +} + +.search-button-field:hover { + border-color: var(--ast-navbar-active-border-color); + color: var(--ast-navbar-hover-color); + font-weight: bold; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); +} + +/** +* +* Side column size (first and second column from left) +* +*/ + +.col-md-3 { + flex: 0 0 20%; + max-width: 20%; +} + +a.headerlink { + color: #222; +} + +@media (min-width: 1200px) { + .container, + .container-lg, + .container-md, + .container-sm, + .container-xl { + max-width: 1200px; + } +} + +@media (min-width: 1600px) { + .container, + .container-lg, + .container-md, + .container-sm, + .container-xl { + max-width: 1600px; + } +} + +/** +* +* Navigation column (according to side column) +* _header.scss +* +*/ +.bd-header .navbar-header-items__start { + width: fit-content; + padding-right: 3rem; +} +/** +* header logo +*/ + +.bd-main .bd-content { + display: flex; + height: 100%; + justify-content: end; +} + +.bd-main .bd-content .bd-article-container .bd-article { + padding-left: 1rem; + padding-top: 1rem; + padding-right: 1rem; +} + +/** +* Bold font weight for **code** +*/ + +b, +strong { + font-weight: 900; +} + +/** +* _code.scss related changes +*/ +.docutils { + font-family: var(--pst-font-family-monospace); + font-weight: 500; +} + +#pst-back-to-top { + background: var(--ast-color-link); + color: var(--ast-color-text); +} + +/** +* _api.scss related changes +*/ + +.sig-prename.descclassname { + display: none; +} /* hide the class 'descclassname' for autoapi */ + +.sig { + font-family: "Consolas", "Menlo", "DejaVu Sans Mono", + "Bitstream Vera Sans Mono", monospace; +} + +.sig-name.descname { + color: var(--pst-color-inline-code); +} + +.sig-name { + color: var(--pst-color-sig); +} + +/** +* highlighted objects inside the api reference +*/ +dt:target, +span.highlighted { + background-color: var(--pst-color-codecell) !important; +} + +/** +* Increase empty-space around classes, methods, properties, etc. that are descendants +* of other items +*/ +dl.class dl.py { + margin-top: 2.5em; + margin-bottom: 2.5em; +} + +/** +* image padding before and after +*/ + +img { + padding-top: 1em; + padding-bottom: 1em; +} + +html[data-theme="dark"] .bd-content img:not(.only-dark):not(.dark-light) { + background: transparent; +} + +img.logo__image { + padding-top: 0rem; + padding-bottom: 0rem; +} + +/** +*Nav-bar entity right side. +*/ + +.list-group-item.active { + z-index: 2; + color: var(--pst-color-text-base) !important; +} + +/** +* admontions +*/ + +div.deprecated { + border-color: var(--pst-color-danger); + background-color: #dc354514; +} + +div.deprecated, +div.versionadded, +div.versionchanged { + background-color: transparent; +} + +.admonition, +div.admonition { + background-color: var(--pst-color-on-surface); +} + +/** +* Select only divisions that contain a dataframe, with enough specificity to override pydata css +*/ +div.nboutput + div.output_area.rendered_html.docutils.container:has(table.dataframe) { + background-color: transparent; +} + +aside.topic > p { + color: var(--pst-color-text-base) !important; +} + +/** +* search hide match +*/ + +div#searchbox p.highlight-link a { + background-color: var(--pst-color-search-match); +} + +.header-article__inner { + padding: 0 1rem; +} + +/** +* +* _links.scss +*/ + +/** +* links on paragraphs +*/ +a { + color: var(--ast-color-link); + text-decoration: none; +} + +a:active { + color: var(--ast-color-link-active); +} + +a:hover, +a:active:hover { + color: var(--ast-color-link-hover); + text-decoration: underline; +} + +a:visited:hover { + color: var(--ast-color-link-visited-hover); +} + +a:visited { + color: var(--ast-color-link-visited); +} + +a:focus-visible { + color: var(--ast-color-link); + box-shadow: var(--ast-ring-shadow-focused); +} + +a > code { + color: var(--ast-color-inline-code); +} + +code.literal { + color: var(--ast-color-inline-code); + font-family: "open sans", sans-serif; +} + +nav.bd-links li > a:focus-visible, +.nav-link:focus-visible, +a.nav-link.pst-navbar-icon:focus-visible, +.toc-entry a.nav-link:focus-visible, +nav.bd-links .current > a:focus-visible { + box-shadow: var(--ast-ring-shadow-focused); + outline: none; +} + +/** +* Admonitions +*/ + +.admonition > .admonition-title, +div.admonition > .admonition-title { + color: var(--ast-admonitions-color); + font-size: var(--ast-admonitions-font-size); + background-color: transparent !important; /* important tag because the admonition has a background color */ + margin-left: 8px; +} + +/** +* Admonitions icons +*/ +.admonition > .admonition-title:after, +div.admonition > .admonition-title:after, +span.versionmodified:before { + font-size: var(--ast-admonitions-icon-size); + height: var(--ast-admonition-icon-height); + width: var(--ast-admonition-icon-width); + left: 0px; +} + +span.versionmodified:before { + margin-right: 16px; /* separate component, to alligh with title, 8px padding + 8px padding from icon */ +} + +/** +* Admonitions title +*/ + +.admonition p.admonition-title ~ *, +div.admonition p.admonition-title ~ * { + margin-left: 40px; /* separate component, to alligh with title, 8px padding + 24px icon + 8px padding from icon */ + margin-right: 8px; + margin-top: 0px; +} + +.admonition, +div.admonition { + border: 2px solid; + padding: var(--ast-admonitions-padding); + box-shadow: none !important; /* important tag because the admonition has a box-shadow from pydata sphinx theme*/ + border-radius: var(--ast-admonitions-border-radius); +} + +/* warning attention caution important, warning */ + +.admonition.attention > .admonition-title:after, +div.admonition.attention > .admonition-title:after, +.admonition.caution > .admonition-title:after, +div.admonition.caution > .admonition-title:after, +.admonition.important > .admonition-title:after, +div.admonition.important > .admonition-title:after, +.admonition.warning > .admonition-title:after, +div.admonition.warning > .admonition-title:after { + color: var(--ast-admonition-warning-icon); +} + +.admonition.caution, +div.admonition.caution, +.admonition.attention, +div.admonition.attention, +.admonition.important, +div.admonition.important, +.admonition.warning, +div.admonition.warning { + border-color: var(--ast-admonition-warning-border); +} + +/* danger are error, danger, depreciated */ + +.admonition.danger > .admonition-title:after, +div.admonition.danger > .admonition-title:after, +.admonition.error > .admonition-title:after, +div.admonition.error > .admonition-title:after, +span.depreciated.changed:before { + color: var(--ast-admonition-danger-icon); +} + +.admonition.danger, +div.admonition.danger, +.admonition.error, +div.admonition.error, +div.deprecated { + border-color: var(--ast-admonition-danger-border); +} + +/*info are hint, note, see also, tip */ + +.admonition.info > .admonition-title:after, +div.admonition.info > .admonition-title:after, +.admonition.hint > .admonition-title:after, +div.admonition.hint > .admonition-title:after, +.admonition.note > .admonition-title:after, +div.admonition.note > .admonition-title:after, +.admonition.seealso > .admonition-title:after, +div.admonition.seealso > .admonition-title:after, +.admonition.tip > .admonition-title:after, +div.admonition.tip > .admonition-title:after { + color: var(--ast-admonition-info-icon); +} + +.admonition.info, +div.admonition.info, +.admonition.hint, +div.admonition.hint, +.admonition.note, +div.admonition.note, +.admonition.seealso, +div.admonition.seealso, +.admonition.tip, +div.admonition.tip { + border-color: var(--ast-admonition-info-border); +} + +/* success is version-added */ + +span.versionadded.changed:before { + color: var(--ast-admonition-success-icon); +} + +div.versionadded { + border-color: var(--ast-admonition-success-border); +} + +/* neutral is todo, version-change, topic */ + +div.deprecated, +div.versionadded, +div.versionchanged { + border-width: 2px; + border-style: solid; + padding: var(--ast-admonitions-padding); + border-radius: var(--ast-admonitions-border-radius); + box-shadow: none !important; /* important tag because the admonition has a box-shadow from pydata sphinx theme*/ +} + +div.deprecated > p, +div.versionadded > p, +div.versionchanged > p { + margin-left: 8px; +} + +span.versionmodified.changed:before, +.admonition.admonition-todo > .admonition-title:after, +div.admonition.admonition-todo > .admonition-title:after { + color: var(--ast-admonition-neutral-icon); +} + +.admonition.admonition-todo, +div.admonition.admonition-todo, +aside.topic, +div.versionchanged { + border-color: var(--ast-admonition-neutral-border); +} + +/** +* Dropdown _header.scss +*/ +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle { + color: var(--ast-navbar-color); + font-weight: 600; + font-size: var(--bs-nav-link-font-size); + border-radius: 4px; + border-color: var(--ast-dropdown-header-border); +} + +.bd-header ul.navbar-nav > li.nav-item.dropdown > .dropdown-toggle:hover { + color: var(--ast-navbar-hover-color); + border-bottom: none; + box-shadow: var(--ast-box-shadow-hover); +} + +.bd-header ul.navbar-nav .dropdown .dropdown-menu .dropdown-item { + color: var(--ast-navbar-color); + font-size: var(--bs-nav-link-font-size); + font-weight: 600; + border-radius: 4px; + border-color: var(--ast-dropdown-header-border); +} + +/** +* Dropdown _header.scss +*/ + +.version-switcher__menu a.list-group-item { + background-color: var(--ast-color-enable-card-background); + width: 200px; + border: none; + filter: drop-shadow(var(--ast-box-shadow-active)); + color: var(--ast-navbar-hover-color); + font-size: var(--ast-nav-link-font-size); + height: 40px; + padding: 0px 16px; + text-decoration: none; + border-radius: 4px; +} + +button.btn.version-switcher__button { + background-color: transparent; + border-color: var(--ast-navbar-active-border-color); + color: var(--ast-navbar-color); + font-size: var(--ast-nav-link-font-size); +} + +button.btn.version-switcher__button:hover { + border-color: var(--ast-navbar-active-border-color); + color: var(--ast-navbar-hover-color); +} + +.version-switcher__menu a.list-group-item:hover { + background-color: var(--ast-color-hover-card-background); + border: none; + color: var(--ast-navbar-hover-color); + font-size: var(--ast-nav-link-font-size); + text-decoration: none; +} + +.version-switcher__menu a.list-group-item:not(:last-child) { + border-bottom: none; +} + +.version-switcher__menu a.list-group-item.active { + box-shadow: none; +} + +.version-switcher__menu { + filter: box-shadow(var(--ast-box-shadow-active)); + border: none; +} + +/** +* Article content (_article.scss) +*/ + +.bd-main .bd-content .bd-article-container { + padding: 8px; + width: 1000px; +} + +.bd-sidebar-primary { + width: 20%; +} diff --git a/version/dev/_static/css/sphinx-design.css b/version/dev/_static/css/sphinx-design.css new file mode 100644 index 00000000..9f918dac --- /dev/null +++ b/version/dev/_static/css/sphinx-design.css @@ -0,0 +1,246 @@ +@import "../design-style.4045f2051d55cab465a707391d5b2007.min.css"; + +/** +* sphinx design button +*/ + +.sd-btn { + font-size: var(--ast-sphinx-design-font-size); + font-weight: 400; + font-family: var(--ast-sphinx-design-font-family); + padding: 8px 16px; + border-radius: var(--ast-sphinx-design-border-radius); +} + +.sd-btn-secondary { + font-size: var(--ast-sphinx-design-font-size); + font-weight: 400; + font-family: var(--ast-sphinx-design-font-family); + padding: 8px 16px; + border-radius: var(--ast-sphinx-design-border-radius); + color: var(--sd-color-secondary-text); + background-color: var(--sd-color-secondary); + border-color: var(--sd-color-secondary); +} + +blockquote { + background-color: var(--pst-color-background); +} + +/* Media query for medium-sized screens */ +@media screen and (max-width: 768px) { + .sd-card .sd-card-header { + font-size: var(--pst-font-size-h6); + } +} + +/* Media query for small-sized screens */ +@media screen and (max-width: 576px) { + .sd-card .sd-card-header { + font-size: var(--pst-font-size-h5); + } + .sd-card { + padding: 4px; + } +} +/** +* Sphinx-design dropdown +*/ + +.bd-content details.sd-dropdown:not([open]) > .sd-card-header { + border-radius: var(--ast-sphinx-design-border-radius); +} + +.bd-content details.sd-dropdown { + color: var(--ast-dropdown-text-color); + width: fit-content; + min-width: 400px; +} + +.bd-content details.sd-dropdown summary.sd-summary-title { + font-family: var(--ast-sphinx-design-font-family); + font-size: var(--ast-sphinx-design-font-size); + background: var(--ast-color-sphinx-design-background) !important; + border: 1px solid var(--ast-dropdown-border-color) !important; + border-radius: var(--ast-sphinx-design-border-radius); + padding: 8px 12px; + text-align: left; +} + +.bd-content details.sd-dropdown summary.sd-summary-title:hover { + background-color: var(--ast-color-hover-card-background) !important; + border: 1px solid var(--ast-dropdown-border-color-hover) !important; + border-radius: var(--ast-sphinx-design-border-radius); +} + +.bd-content + details.sd-dropdown + summary.sd-card-header + + div.sd-summary-content { + background-color: var(--ast-color-sphinx-design-background); + border-left: none !important; +} + +.bd-content + details.sd-dropdown + .sd-summary-title:active + + div.sd-summary-content:active { + background-color: var(--ast-color-enable-card-background); + border-color: var(--ast-color-enable-border); +} + +.bd-content + details.sd-dropdown + .sd-summary-title:hover + + div.sd-summary-content:hover { + background-color: var(--ast-color-hover-card-background); + border-color: var(--ast-color-hover-border); + border-left: none; +} + +.bd-content + details.sd-dropdown + summary.sd-summary-title:focus + + div.sd-summary-content:focus { + background-color: var(--ast-color-sphinx-design-background); + border-radius: var(--ast-sphinx-design-border-radius); + border-color: var(--pst-color-border); + border-left: none; +} + +details.sd-dropdown summary.sd-card-header + div.sd-summary-content { + color: var(--ast-color-sphinx-design-primary); + font-family: var(--ast-sphinx-design-font-family); + font-size: var(--ast-sphinx-design-font-size); +} + +/** +* Sphinx-design tab +*/ + +.bd-content .sd-tab-set > label { + font-family: var(--ast-sphinx-design-font-family); + padding: 12px 0px; + border-style: none none solid none; + color: var(--ast-color-sphinx-design-primary); + font-size: var(--ast-sphinx-design-font-size); + margin-inline-end: 16px; + transform: none; + margin-bottom: 1px; +} + +.bd-content .sd-tab-set > input:checked + label:hover, +.bd-content .sd-tab-set > input:not(:checked, :focus-visible) + label:hover { + color: var(--ast-color-sphinx-design-primary); + font-family: var(--ast-sphinx-design-font-family); +} + +.bd-content .sd-tab-set > input + label:focus-visible, +.bd-content + .sd-tab-set + > input:not(:checked, :focus-visible) + + label:focus-visible { + background-color: var(--ast-background-tab-focus); + border-color: transparent transparent var(--ast-tab-border-color-hover) + transparent; + border-width: 0px 0px 2px 0px; + text-decoration-line: none; +} + +.bd-content .sd-tab-set > input:checked + label { + background-color: transparent; + border-color: transparent transparent var(--ast-tab-border-color-active) + transparent; + border-width: 0px 0px 2px 0px; + border-style: none none solid none; + transform: none; +} + +.bd-content .sd-tab-set > input:checked + label:hover { + background-color: var(--ast-background-tab-hover); + border-color: transparent transparent var(--ast-tab-border-color-hover) + transparent; + border-width: 0px 0px 2px 0px; +} + +.bd-content .sd-tab-set > input:not(:checked, :focus-visible) + label { + background-color: transparent; + border-color: transparent transparent var(--ast-tab-border-color) transparent; + border-width: 0px 0px 1px 0px; + text-decoration-line: none; + font-weight: normal; +} + +.bd-content .sd-tab-set > input:not(:checked, :focus-visible) + label:hover { + background-color: var(--ast-background-tab-hover); + border-color: transparent transparent var(--ast-tab-border-color-hover) + transparent; + border-width: 0px 0px 2px 0px; + border-style: none none solid none; + text-decoration: none; +} + +.bd-content .sd-tab-set .sd-tab-content { + border: none; + font-family: var(--ast-sphinx-design-font-family); + font-size: var(--ast-sphinx-design-font-size); + color: var(--ast-color-sphinx-design-primary); +} + +/* Media query for medium-sized screens */ +@media screen and (max-width: 768px) { + .sd-tab-set > input:not(.focus-visible) + label { + font-size: 14px; + } +} + +/* Media query for small-sized screens */ +@media screen and (max-width: 576px) { + .sd-tab-set > input:not(.focus-visible) + label { + font-size: 12px; + } +} + +/** +* Sphinx-design card +*/ + +.bd-content .sd-card .sd-card-body, +.bd-content .sd-card .sd-card-footer { + font-size: var(--ast-sphinx-design-font-size); + border: none; + background-color: var(--ast-color-sphinx-design-background); + font-family: var(--ast-sphinx-design-font-family); + color: var(--ast-color-sphinx-design-primary); + border-radius: 8px; +} + +.bd-content .sd-card .sd-card-title, +.bd-content .sd-card .sd-card-header { + font-size: 16px; + border: none; + background-color: var(--ast-color-sphinx-design-background); + font-family: var(--ast-sphinx-design-font-family); +} + +.bd-content .sd-card { + border: none; + border-radius: 8px; + box-shadow: var(--ast-box-shadow-hover) !important; + color: var(--ast-color-sphinx-design-primary); + background-color: var(--ast-color-sphinx-design-background); +} + +.bd-content .sd-card:hover { + box-shadow: var(--ast-box-shadow-hover) !important; +} + +.sd-hide-link-text:focus { + outline: none; + box-shadow: none; +} + +.bd-content .sd-card .sd-stretched-link:focus-visible:after { + outline: none; + box-shadow: var(--ast-ring-shadow-focused); +} diff --git a/version/dev/_static/css/sphinx-gallery.css b/version/dev/_static/css/sphinx-gallery.css new file mode 100644 index 00000000..dbd25dc2 --- /dev/null +++ b/version/dev/_static/css/sphinx-gallery.css @@ -0,0 +1,56 @@ +@import "ansys-sphinx-theme-variable.css"; + +/** +* Sphinx gallery output cell +*/ + +.highlight pre { + font-size: 0.9em; +} + +/** +* Sphinx gallery download button text +*/ + +a > code.download { + font-family: var(--pst-font-family-base); + color: var(--pst-color-link); + text-decoration: none; + font-weight: normal; +} + +div.sphx-glr-download a, +div.sphx-glr-download a:hover { + background-image: none; + color: var(--ast-sphinx-gallery-download-text); + text-decoration: none; + border-radius: 4px; + height: 36px; + padding: 0px 16px; + display: flex; + align-items: flex-start; + justify-content: center; + flex-wrap: wrap; + flex-direction: column; +} +div.sphx-glr-download code.download, +a.reference.download:before { + color: var(--ast-sphinx-gallery-download-text); +} +div.sphx-glr-download a:hover { + background-color: var(--ast-sphinx-gallery-download-background-hover); +} + +div.sphx-glr-download a { + background-color: var(--ast-sphinx-gallery-download-background); +} + +.docutils.container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-content: center; + justify-content: flex-start; + gap: 10px; + margin: initial; +} diff --git a/version/dev/_static/css/table-custom.css b/version/dev/_static/css/table-custom.css new file mode 100644 index 00000000..5411d1b7 --- /dev/null +++ b/version/dev/_static/css/table-custom.css @@ -0,0 +1,116 @@ +/** +* Table +* +* the table variables. +*/ + +.table { + --bs-table-bg: var(--ast-color-table-background); + border-spacing: 0; + border-collapse: separate; + overflow: hidden; + vertical-align: middle; + overflow-y: scroll; + scrollbar-width: none; + -ms-overflow-style: none; + border-color: var(--ast-table-outer-border); + background-color: var(--ast-color-table-background); +} + +tbody, +td, +tfoot, +th, +thead, +tr { + border-bottom: 1px solid var(--ast-color-table-inner-border); + background-color: var(--ast-color-table-background); + font-family: var(--ast-font-family-base); + font-size: var(--ast-table-font-size); +} + +.table > :not(caption) > * > * { + padding: 0px 16px; +} + +/** +* Table header +*/ +th { + line-height: 40px; + color: var(--ast-color-table-header-text) !important; + font-size: var(--ast-table-header-font-size) !important; +} + +/** +* Table body +*/ + +tr { + line-height: var(--ast-global-line-height); + height: 56px; + color: var(--ast-color-table-cell-text); +} + +/** +* Table hover +*/ + +tbody :hover, +td :hover, +tfoot :hover, +th :hover, +thead :hover, +tr :hover { + background-color: var(--ast-color-table-row-hover-bg); + font-family: var(--ast-font-family-base); +} + +.table :hover { + background-color: var(--ast-color-table-row-hover-bg); +} + +/** +* Table active +*/ + +.table :active { + background-color: var(--ast-color-table-active-bg); +} +/** +* Table dataframes +*/ + +table.dataframe tr { + font-size: var(--ast-table-font-size); + line-height: 56px; + color: var(--ast-color-table-cell-text); +} + +table.dataframe th { + font-size: var(--ast-table-font-size); + line-height: 40px; + color: var(--ast-color-table-header-text) !important; +} + +table.dataframe :hover { + background-color: var(--ast-color-table-row-hover-bg); + font-family: var(--ast-font-family-base); +} + +table.dataframe :active { + background-color: var(--ast-color-table-active-bg); + font-family: var(--ast-font-family-base); +} + +table.dataframe { + background-color: var(--ast-color-table-background); +} + +.table td ~ td, +.table td ~ th, +.table th ~ td, +.table th ~ th, +.bd-content .nboutput .output_area.rendered_html table.dataframe th ~ td { + border-left: 1px solid var(--ast-color-table-inner-border); +} diff --git a/version/dev/_static/design-tabs.js b/version/dev/_static/design-tabs.js new file mode 100644 index 00000000..2952d2e2 --- /dev/null +++ b/version/dev/_static/design-tabs.js @@ -0,0 +1,101 @@ +// @ts-check + +// Extra JS capability for selected tabs to be synced +// The selection is stored in local storage so that it persists across page loads. + +/** + * @type {Record} + */ +let sd_id_to_elements = {}; +const storageKeyPrefix = "sphinx-design-tab-id-"; + +/** + * Create a key for a tab element. + * @param {HTMLElement} el - The tab element. + * @returns {[string, string, string] | null} - The key. + * + */ +function create_key(el) { + let syncId = el.getAttribute("data-sync-id"); + let syncGroup = el.getAttribute("data-sync-group"); + if (!syncId || !syncGroup) return null; + return [syncGroup, syncId, syncGroup + "--" + syncId]; +} + +/** + * Initialize the tab selection. + * + */ +function ready() { + // Find all tabs with sync data + + /** @type {string[]} */ + let groups = []; + + document.querySelectorAll(".sd-tab-label").forEach((label) => { + if (label instanceof HTMLElement) { + let data = create_key(label); + if (data) { + let [group, id, key] = data; + + // add click event listener + // @ts-ignore + label.onclick = onSDLabelClick; + + // store map of key to elements + if (!sd_id_to_elements[key]) { + sd_id_to_elements[key] = []; + } + sd_id_to_elements[key].push(label); + + if (groups.indexOf(group) === -1) { + groups.push(group); + // Check if a specific tab has been selected via URL parameter + const tabParam = new URLSearchParams(window.location.search).get( + group + ); + if (tabParam) { + console.log( + "sphinx-design: Selecting tab id for group '" + + group + + "' from URL parameter: " + + tabParam + ); + window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); + } + } + + // Check is a specific tab has been selected previously + let previousId = window.sessionStorage.getItem( + storageKeyPrefix + group + ); + if (previousId === id) { + // console.log( + // "sphinx-design: Selecting tab from session storage: " + id + // ); + // @ts-ignore + label.previousElementSibling.checked = true; + } + } + } + }); +} + +/** + * Activate other tabs with the same sync id. + * + * @this {HTMLElement} - The element that was clicked. + */ +function onSDLabelClick() { + let data = create_key(this); + if (!data) return; + let [group, id, key] = data; + for (const label of sd_id_to_elements[key]) { + if (label === this) continue; + // @ts-ignore + label.previousElementSibling.checked = true; + } + window.sessionStorage.setItem(storageKeyPrefix + group, id); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/version/dev/_static/doctools.js b/version/dev/_static/doctools.js new file mode 100644 index 00000000..4d67807d --- /dev/null +++ b/version/dev/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/version/dev/_static/documentation_options.js b/version/dev/_static/documentation_options.js new file mode 100644 index 00000000..95b041a1 --- /dev/null +++ b/version/dev/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.1.dev0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: true, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/version/dev/_static/file.png b/version/dev/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/version/dev/_static/file.png differ diff --git a/version/dev/_static/fonts/SourceSansPro-Light.ttf b/version/dev/_static/fonts/SourceSansPro-Light.ttf new file mode 100644 index 00000000..348871ac Binary files /dev/null and b/version/dev/_static/fonts/SourceSansPro-Light.ttf differ diff --git a/version/dev/_static/fonts/SourceSansPro-Regular.ttf b/version/dev/_static/fonts/SourceSansPro-Regular.ttf new file mode 100644 index 00000000..b422bf43 Binary files /dev/null and b/version/dev/_static/fonts/SourceSansPro-Regular.ttf differ diff --git a/version/dev/_static/fonts/SourceSansPro-SemiBold.ttf b/version/dev/_static/fonts/SourceSansPro-SemiBold.ttf new file mode 100644 index 00000000..2908e0d7 Binary files /dev/null and b/version/dev/_static/fonts/SourceSansPro-SemiBold.ttf differ diff --git a/version/dev/_static/graphviz.css b/version/dev/_static/graphviz.css new file mode 100644 index 00000000..027576e3 --- /dev/null +++ b/version/dev/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/version/dev/_static/js/download_target_blank.js b/version/dev/_static/js/download_target_blank.js new file mode 100644 index 00000000..9f84c70f --- /dev/null +++ b/version/dev/_static/js/download_target_blank.js @@ -0,0 +1,6 @@ +/* Add target="_blank" attribute to all hyperlinks generated by the ReST :download: directive. + * This will ensure the links open in a new tab. */ + +$(document).ready(function () { + $("a.download").attr("target", "_blank"); +}); diff --git a/version/dev/_static/js/meilisearch_theme_wrap.js b/version/dev/_static/js/meilisearch_theme_wrap.js new file mode 100644 index 00000000..8ebc51dd --- /dev/null +++ b/version/dev/_static/js/meilisearch_theme_wrap.js @@ -0,0 +1,62 @@ +require.config({ + paths: { + docsSearchBar: + "https://cdn.jsdelivr.net/npm/docs-searchbar.js@2.5.0/dist/cdn/docs-searchbar.min", + }, +}); + +require(["docsSearchBar"], function (docsSearchBar) { + document.body.style.overflow = "hidden !important"; + // Initialize the MeiliSearch bar with the given API key and host + var theSearchBar = docsSearchBar({ + hostUrl: HOST_URL, + apiKey: API_KEY, + indexUid: indexUid, + inputSelector: "form.bd-search input", + debug: true, // Set debug to true if you want to inspect the dropdown + meilisearchOptions: { + limit: 10, + }, + }); + + // Function to show the magnifier icon + function showMagnifierIcon() { + var searchIcon = document.getElementById("search-icon"); + searchIcon.classList.remove("fa-spinner", "fa-spin"); // Remove spinner classes + searchIcon.classList.add("fa-magnifying-glass"); // Add magnifier icon class + } + + // Function to show the spinner icon + function showSpinnerIcon() { + var searchIcon = document.getElementById("search-icon"); + if (searchIcon) { + searchIcon.classList.remove("fa-magnifying-glass"); // Remove magnifier icon class + searchIcon.classList.add("fa-spinner", "fa-spin"); // Add spinner classes + } + } + + document + .getElementById("form.bd-search input") + .addEventListener("input", function () { + const inputValue = this.value.trim(); // Trim whitespace from input value + // Show the spinner icon only when there is input and no suggestions + if ( + inputValue && + document.querySelectorAll(".dsb-suggestion").length === 0 + ) { + showSpinnerIcon(); + } else { + // Hide the spinner icon when there are suggestions + showMagnifierIcon(); + } + }); + + // Listen for changes in the dropdown selector and update the index uid and suggestion accordingly + document + .getElementById("indexUidSelector") + .addEventListener("change", function () { + theSearchBar.indexUid = this.value; + theSearchBar.suggestionIndexUid = this.value; + theSearchBar.autocomplete.autocomplete.setVal(""); + }); +}); diff --git a/version/dev/_static/js/pydata_search.js b/version/dev/_static/js/pydata_search.js new file mode 100644 index 00000000..58a32631 --- /dev/null +++ b/version/dev/_static/js/pydata_search.js @@ -0,0 +1,9 @@ +let searchInput = document.querySelector("form.bd-search input"); +if (searchInput) { + searchInput.focus(); + searchInput.select(); + console.log("[PST]: Set focus on search field."); +} +src = "{{ pathto('_static/searchtools.js', 1) }}"; +src = "{{ pathto('_static/language_data.js', 1) }}"; +src = "{{ pathto('searchindex.js', 1) }}"; diff --git a/version/dev/_static/js/table.js b/version/dev/_static/js/table.js new file mode 100644 index 00000000..a080ead1 --- /dev/null +++ b/version/dev/_static/js/table.js @@ -0,0 +1,3 @@ +$(document).ready(function () { + $("table.datatable").DataTable(); +}); diff --git a/version/dev/_static/language_data.js b/version/dev/_static/language_data.js new file mode 100644 index 00000000..fd5e0d74 --- /dev/null +++ b/version/dev/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/version/dev/_static/ldf.png b/version/dev/_static/ldf.png new file mode 100644 index 00000000..43646374 Binary files /dev/null and b/version/dev/_static/ldf.png differ diff --git a/version/dev/_static/logos/ansys-favicon.png b/version/dev/_static/logos/ansys-favicon.png new file mode 100644 index 00000000..cfb2e535 Binary files /dev/null and b/version/dev/_static/logos/ansys-favicon.png differ diff --git a/version/dev/_static/logos/ansys_logo_black.jpg b/version/dev/_static/logos/ansys_logo_black.jpg new file mode 100644 index 00000000..7f737335 Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_black.jpg differ diff --git a/version/dev/_static/logos/ansys_logo_black_cropped.jpg b/version/dev/_static/logos/ansys_logo_black_cropped.jpg new file mode 100644 index 00000000..05d98e6c Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_black_cropped.jpg differ diff --git a/version/dev/_static/logos/ansys_logo_transparent_black.png b/version/dev/_static/logos/ansys_logo_transparent_black.png new file mode 100644 index 00000000..8ce219af Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_transparent_black.png differ diff --git a/version/dev/_static/logos/ansys_logo_transparent_white.png b/version/dev/_static/logos/ansys_logo_transparent_white.png new file mode 100644 index 00000000..6121882b Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_transparent_white.png differ diff --git a/version/dev/_static/logos/ansys_logo_white.pdf b/version/dev/_static/logos/ansys_logo_white.pdf new file mode 100644 index 00000000..fceb89b3 Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_white.pdf differ diff --git a/version/dev/_static/logos/ansys_logo_white_cropped.pdf b/version/dev/_static/logos/ansys_logo_white_cropped.pdf new file mode 100644 index 00000000..ad122b15 Binary files /dev/null and b/version/dev/_static/logos/ansys_logo_white_cropped.pdf differ diff --git a/version/dev/_static/logos/pyansys-logo-black-cropped.png b/version/dev/_static/logos/pyansys-logo-black-cropped.png new file mode 100644 index 00000000..e28bc3de Binary files /dev/null and b/version/dev/_static/logos/pyansys-logo-black-cropped.png differ diff --git a/version/dev/_static/logos/pyansys-logo-white-cropped.png b/version/dev/_static/logos/pyansys-logo-white-cropped.png new file mode 100644 index 00000000..91b50f98 Binary files /dev/null and b/version/dev/_static/logos/pyansys-logo-white-cropped.png differ diff --git a/version/dev/_static/logos/pyansys_dark.png b/version/dev/_static/logos/pyansys_dark.png new file mode 100644 index 00000000..b0ff9e19 Binary files /dev/null and b/version/dev/_static/logos/pyansys_dark.png differ diff --git a/version/dev/_static/logos/pyansys_dark_square.png b/version/dev/_static/logos/pyansys_dark_square.png new file mode 100644 index 00000000..2b271562 Binary files /dev/null and b/version/dev/_static/logos/pyansys_dark_square.png differ diff --git a/version/dev/_static/logos/pyansys_light.png b/version/dev/_static/logos/pyansys_light.png new file mode 100644 index 00000000..9f31babd Binary files /dev/null and b/version/dev/_static/logos/pyansys_light.png differ diff --git a/version/dev/_static/logos/pyansys_light_square.png b/version/dev/_static/logos/pyansys_light_square.png new file mode 100644 index 00000000..3e0706a5 Binary files /dev/null and b/version/dev/_static/logos/pyansys_light_square.png differ diff --git a/version/dev/_static/logos/pyansys_logo_transparent_black.png b/version/dev/_static/logos/pyansys_logo_transparent_black.png new file mode 100644 index 00000000..a20b724c Binary files /dev/null and b/version/dev/_static/logos/pyansys_logo_transparent_black.png differ diff --git a/version/dev/_static/logos/pyansys_logo_transparent_white.png b/version/dev/_static/logos/pyansys_logo_transparent_white.png new file mode 100644 index 00000000..a507ee8e Binary files /dev/null and b/version/dev/_static/logos/pyansys_logo_transparent_white.png differ diff --git a/version/dev/_static/logos/watermark.pdf b/version/dev/_static/logos/watermark.pdf new file mode 100644 index 00000000..202d1e69 Binary files /dev/null and b/version/dev/_static/logos/watermark.pdf differ diff --git a/version/dev/_static/minus.png b/version/dev/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/version/dev/_static/minus.png differ diff --git a/version/dev/_static/nbsphinx-broken-thumbnail.svg b/version/dev/_static/nbsphinx-broken-thumbnail.svg new file mode 100644 index 00000000..4919ca88 --- /dev/null +++ b/version/dev/_static/nbsphinx-broken-thumbnail.svg @@ -0,0 +1,9 @@ + + + + diff --git a/version/dev/_static/nbsphinx-code-cells.css b/version/dev/_static/nbsphinx-code-cells.css new file mode 100644 index 00000000..f5629508 --- /dev/null +++ b/version/dev/_static/nbsphinx-code-cells.css @@ -0,0 +1,259 @@ +/* remove conflicting styling from Sphinx themes */ +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt *, +div.nbinput.container div.input_area pre, +div.nboutput.container div.output_area pre, +div.nbinput.container div.input_area .highlight, +div.nboutput.container div.output_area .highlight { + border: none; + padding: 0; + margin: 0; + box-shadow: none; +} + +div.nbinput.container > div[class*=highlight], +div.nboutput.container > div[class*=highlight] { + margin: 0; +} + +div.nbinput.container div.prompt *, +div.nboutput.container div.prompt * { + background: none; +} + +div.nboutput.container div.output_area .highlight, +div.nboutput.container div.output_area pre { + background: unset; +} + +div.nboutput.container div.output_area div.highlight { + color: unset; /* override Pygments text color */ +} + +/* avoid gaps between output lines */ +div.nboutput.container div[class*=highlight] pre { + line-height: normal; +} + +/* input/output containers */ +div.nbinput.container, +div.nboutput.container { + display: -webkit-flex; + display: flex; + align-items: flex-start; + margin: 0; + width: 100%; +} +@media (max-width: 540px) { + div.nbinput.container, + div.nboutput.container { + flex-direction: column; + } +} + +/* input container */ +div.nbinput.container { + padding-top: 5px; +} + +/* last container */ +div.nblast.container { + padding-bottom: 5px; +} + +/* input prompt */ +div.nbinput.container div.prompt pre, +/* for sphinx_immaterial theme: */ +div.nbinput.container div.prompt pre > code { + color: #307FC1; +} + +/* output prompt */ +div.nboutput.container div.prompt pre, +/* for sphinx_immaterial theme: */ +div.nboutput.container div.prompt pre > code { + color: #BF5B3D; +} + +/* all prompts */ +div.nbinput.container div.prompt, +div.nboutput.container div.prompt { + width: 4.5ex; + padding-top: 5px; + position: relative; + user-select: none; +} + +div.nbinput.container div.prompt > div, +div.nboutput.container div.prompt > div { + position: absolute; + right: 0; + margin-right: 0.3ex; +} + +@media (max-width: 540px) { + div.nbinput.container div.prompt, + div.nboutput.container div.prompt { + width: unset; + text-align: left; + padding: 0.4em; + } + div.nboutput.container div.prompt.empty { + padding: 0; + } + + div.nbinput.container div.prompt > div, + div.nboutput.container div.prompt > div { + position: unset; + } +} + +/* disable scrollbars and line breaks on prompts */ +div.nbinput.container div.prompt pre, +div.nboutput.container div.prompt pre { + overflow: hidden; + white-space: pre; +} + +/* input/output area */ +div.nbinput.container div.input_area, +div.nboutput.container div.output_area { + -webkit-flex: 1; + flex: 1; + overflow: auto; +} +@media (max-width: 540px) { + div.nbinput.container div.input_area, + div.nboutput.container div.output_area { + width: 100%; + } +} + +/* input area */ +div.nbinput.container div.input_area { + border: 1px solid #e0e0e0; + border-radius: 2px; + /*background: #f5f5f5;*/ +} + +/* override MathJax center alignment in output cells */ +div.nboutput.container div[class*=MathJax] { + text-align: left !important; +} + +/* override sphinx.ext.imgmath center alignment in output cells */ +div.nboutput.container div.math p { + text-align: left; +} + +/* standard error */ +div.nboutput.container div.output_area.stderr { + background: #fdd; +} + +/* ANSI colors */ +.ansi-black-fg { color: #3E424D; } +.ansi-black-bg { background-color: #3E424D; } +.ansi-black-intense-fg { color: #282C36; } +.ansi-black-intense-bg { background-color: #282C36; } +.ansi-red-fg { color: #E75C58; } +.ansi-red-bg { background-color: #E75C58; } +.ansi-red-intense-fg { color: #B22B31; } +.ansi-red-intense-bg { background-color: #B22B31; } +.ansi-green-fg { color: #00A250; } +.ansi-green-bg { background-color: #00A250; } +.ansi-green-intense-fg { color: #007427; } +.ansi-green-intense-bg { background-color: #007427; } +.ansi-yellow-fg { color: #DDB62B; } +.ansi-yellow-bg { background-color: #DDB62B; } +.ansi-yellow-intense-fg { color: #B27D12; } +.ansi-yellow-intense-bg { background-color: #B27D12; } +.ansi-blue-fg { color: #208FFB; } +.ansi-blue-bg { background-color: #208FFB; } +.ansi-blue-intense-fg { color: #0065CA; } +.ansi-blue-intense-bg { background-color: #0065CA; } +.ansi-magenta-fg { color: #D160C4; } +.ansi-magenta-bg { background-color: #D160C4; } +.ansi-magenta-intense-fg { color: #A03196; } +.ansi-magenta-intense-bg { background-color: #A03196; } +.ansi-cyan-fg { color: #60C6C8; } +.ansi-cyan-bg { background-color: #60C6C8; } +.ansi-cyan-intense-fg { color: #258F8F; } +.ansi-cyan-intense-bg { background-color: #258F8F; } +.ansi-white-fg { color: #C5C1B4; } +.ansi-white-bg { background-color: #C5C1B4; } +.ansi-white-intense-fg { color: #A1A6B2; } +.ansi-white-intense-bg { background-color: #A1A6B2; } + +.ansi-default-inverse-fg { color: #FFFFFF; } +.ansi-default-inverse-bg { background-color: #000000; } + +.ansi-bold { font-weight: bold; } +.ansi-underline { text-decoration: underline; } + + +div.nbinput.container div.input_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight] > pre, +div.nboutput.container div.output_area div[class*=highlight].math, +div.nboutput.container div.output_area.rendered_html, +div.nboutput.container div.output_area > div.output_javascript, +div.nboutput.container div.output_area:not(.rendered_html) > img{ + padding: 5px; + margin: 0; +} + +/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */ +div.nbinput.container div.input_area > div[class^='highlight'], +div.nboutput.container div.output_area > div[class^='highlight']{ + overflow-y: hidden; +} + +/* hide copy button on prompts for 'sphinx_copybutton' extension ... */ +.prompt .copybtn, +/* ... and 'sphinx_immaterial' theme */ +.prompt .md-clipboard.md-icon { + display: none; +} + +/* Some additional styling taken form the Jupyter notebook CSS */ +.jp-RenderedHTMLCommon table, +div.rendered_html table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 12px; + table-layout: fixed; +} +.jp-RenderedHTMLCommon thead, +div.rendered_html thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} +.jp-RenderedHTMLCommon tr, +.jp-RenderedHTMLCommon th, +.jp-RenderedHTMLCommon td, +div.rendered_html tr, +div.rendered_html th, +div.rendered_html td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.jp-RenderedHTMLCommon th, +div.rendered_html th { + font-weight: bold; +} +.jp-RenderedHTMLCommon tbody tr:nth-child(odd), +div.rendered_html tbody tr:nth-child(odd) { + background: #f5f5f5; +} +.jp-RenderedHTMLCommon tbody tr:hover, +div.rendered_html tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + diff --git a/version/dev/_static/nbsphinx-gallery.css b/version/dev/_static/nbsphinx-gallery.css new file mode 100644 index 00000000..365c27a9 --- /dev/null +++ b/version/dev/_static/nbsphinx-gallery.css @@ -0,0 +1,31 @@ +.nbsphinx-gallery { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 5px; + margin-top: 1em; + margin-bottom: 1em; +} + +.nbsphinx-gallery > a { + padding: 5px; + border: 1px dotted currentColor; + border-radius: 2px; + text-align: center; +} + +.nbsphinx-gallery > a:hover { + border-style: solid; +} + +.nbsphinx-gallery img { + max-width: 100%; + max-height: 100%; +} + +.nbsphinx-gallery > a > div:first-child { + display: flex; + align-items: start; + justify-content: center; + height: 120px; + margin-bottom: 5px; +} diff --git a/version/dev/_static/nbsphinx-no-thumbnail.svg b/version/dev/_static/nbsphinx-no-thumbnail.svg new file mode 100644 index 00000000..9dca7588 --- /dev/null +++ b/version/dev/_static/nbsphinx-no-thumbnail.svg @@ -0,0 +1,9 @@ + + + + diff --git a/version/dev/_static/plus.png b/version/dev/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/version/dev/_static/plus.png differ diff --git a/version/dev/_static/pygments.css b/version/dev/_static/pygments.css new file mode 100644 index 00000000..3a29d014 --- /dev/null +++ b/version/dev/_static/pygments.css @@ -0,0 +1,160 @@ +html[data-theme="light"] .highlight pre { line-height: 125%; } +html[data-theme="light"] .highlight td.linenos .normal { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos { color: #666666; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="light"] .highlight .hll { background-color: #ffffcc } +html[data-theme="light"] .highlight { background: #f0f0f0; } +html[data-theme="light"] .highlight .c { color: #60a0b0; font-style: italic } /* Comment */ +html[data-theme="light"] .highlight .err { border: 1px solid #FF0000 } /* Error */ +html[data-theme="light"] .highlight .k { color: #007020; font-weight: bold } /* Keyword */ +html[data-theme="light"] .highlight .o { color: #666666 } /* Operator */ +html[data-theme="light"] .highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */ +html[data-theme="light"] .highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ +html[data-theme="light"] .highlight .cp { color: #007020 } /* Comment.Preproc */ +html[data-theme="light"] .highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */ +html[data-theme="light"] .highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ +html[data-theme="light"] .highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ +html[data-theme="light"] .highlight .gd { color: #A00000 } /* Generic.Deleted */ +html[data-theme="light"] .highlight .ge { font-style: italic } /* Generic.Emph */ +html[data-theme="light"] .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +html[data-theme="light"] .highlight .gr { color: #FF0000 } /* Generic.Error */ +html[data-theme="light"] .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +html[data-theme="light"] .highlight .gi { color: #00A000 } /* Generic.Inserted */ +html[data-theme="light"] .highlight .go { color: #888888 } /* Generic.Output */ +html[data-theme="light"] .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +html[data-theme="light"] .highlight .gs { font-weight: bold } /* Generic.Strong */ +html[data-theme="light"] .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +html[data-theme="light"] .highlight .gt { color: #0044DD } /* Generic.Traceback */ +html[data-theme="light"] .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +html[data-theme="light"] .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +html[data-theme="light"] .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +html[data-theme="light"] .highlight .kp { color: #007020 } /* Keyword.Pseudo */ +html[data-theme="light"] .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +html[data-theme="light"] .highlight .kt { color: #902000 } /* Keyword.Type */ +html[data-theme="light"] .highlight .m { color: #40a070 } /* Literal.Number */ +html[data-theme="light"] .highlight .s { color: #4070a0 } /* Literal.String */ +html[data-theme="light"] .highlight .na { color: #4070a0 } /* Name.Attribute */ +html[data-theme="light"] .highlight .nb { color: #007020 } /* Name.Builtin */ +html[data-theme="light"] .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +html[data-theme="light"] .highlight .no { color: #60add5 } /* Name.Constant */ +html[data-theme="light"] .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +html[data-theme="light"] .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +html[data-theme="light"] .highlight .ne { color: #007020 } /* Name.Exception */ +html[data-theme="light"] .highlight .nf { color: #06287e } /* Name.Function */ +html[data-theme="light"] .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +html[data-theme="light"] .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +html[data-theme="light"] .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +html[data-theme="light"] .highlight .nv { color: #bb60d5 } /* Name.Variable */ +html[data-theme="light"] .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +html[data-theme="light"] .highlight .w { color: #bbbbbb } /* Text.Whitespace */ +html[data-theme="light"] .highlight .mb { color: #40a070 } /* Literal.Number.Bin */ +html[data-theme="light"] .highlight .mf { color: #40a070 } /* Literal.Number.Float */ +html[data-theme="light"] .highlight .mh { color: #40a070 } /* Literal.Number.Hex */ +html[data-theme="light"] .highlight .mi { color: #40a070 } /* Literal.Number.Integer */ +html[data-theme="light"] .highlight .mo { color: #40a070 } /* Literal.Number.Oct */ +html[data-theme="light"] .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +html[data-theme="light"] .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +html[data-theme="light"] .highlight .sc { color: #4070a0 } /* Literal.String.Char */ +html[data-theme="light"] .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +html[data-theme="light"] .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +html[data-theme="light"] .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +html[data-theme="light"] .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +html[data-theme="light"] .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +html[data-theme="light"] .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +html[data-theme="light"] .highlight .sx { color: #c65d09 } /* Literal.String.Other */ +html[data-theme="light"] .highlight .sr { color: #235388 } /* Literal.String.Regex */ +html[data-theme="light"] .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +html[data-theme="light"] .highlight .ss { color: #517918 } /* Literal.String.Symbol */ +html[data-theme="light"] .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +html[data-theme="light"] .highlight .fm { color: #06287e } /* Name.Function.Magic */ +html[data-theme="light"] .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +html[data-theme="light"] .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +html[data-theme="light"] .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +html[data-theme="light"] .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +html[data-theme="light"] .highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ +html[data-theme="dark"] .highlight pre { line-height: 125%; } +html[data-theme="dark"] .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +html[data-theme="dark"] .highlight .hll { background-color: #49483e } +html[data-theme="dark"] .highlight { background: #272822; color: #f8f8f2 } +html[data-theme="dark"] .highlight .c { color: #959077 } /* Comment */ +html[data-theme="dark"] .highlight .err { color: #ed007e; background-color: #1e0010 } /* Error */ +html[data-theme="dark"] .highlight .esc { color: #f8f8f2 } /* Escape */ +html[data-theme="dark"] .highlight .g { color: #f8f8f2 } /* Generic */ +html[data-theme="dark"] .highlight .k { color: #66d9ef } /* Keyword */ +html[data-theme="dark"] .highlight .l { color: #ae81ff } /* Literal */ +html[data-theme="dark"] .highlight .n { color: #f8f8f2 } /* Name */ +html[data-theme="dark"] .highlight .o { color: #ff4689 } /* Operator */ +html[data-theme="dark"] .highlight .x { color: #f8f8f2 } /* Other */ +html[data-theme="dark"] .highlight .p { color: #f8f8f2 } /* Punctuation */ +html[data-theme="dark"] .highlight .ch { color: #959077 } /* Comment.Hashbang */ +html[data-theme="dark"] .highlight .cm { color: #959077 } /* Comment.Multiline */ +html[data-theme="dark"] .highlight .cp { color: #959077 } /* Comment.Preproc */ +html[data-theme="dark"] .highlight .cpf { color: #959077 } /* Comment.PreprocFile */ +html[data-theme="dark"] .highlight .c1 { color: #959077 } /* Comment.Single */ +html[data-theme="dark"] .highlight .cs { color: #959077 } /* Comment.Special */ +html[data-theme="dark"] .highlight .gd { color: #ff4689 } /* Generic.Deleted */ +html[data-theme="dark"] .highlight .ge { color: #f8f8f2; font-style: italic } /* Generic.Emph */ +html[data-theme="dark"] .highlight .ges { color: #f8f8f2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +html[data-theme="dark"] .highlight .gr { color: #f8f8f2 } /* Generic.Error */ +html[data-theme="dark"] .highlight .gh { color: #f8f8f2 } /* Generic.Heading */ +html[data-theme="dark"] .highlight .gi { color: #a6e22e } /* Generic.Inserted */ +html[data-theme="dark"] .highlight .go { color: #66d9ef } /* Generic.Output */ +html[data-theme="dark"] .highlight .gp { color: #ff4689; font-weight: bold } /* Generic.Prompt */ +html[data-theme="dark"] .highlight .gs { color: #f8f8f2; font-weight: bold } /* Generic.Strong */ +html[data-theme="dark"] .highlight .gu { color: #959077 } /* Generic.Subheading */ +html[data-theme="dark"] .highlight .gt { color: #f8f8f2 } /* Generic.Traceback */ +html[data-theme="dark"] .highlight .kc { color: #66d9ef } /* Keyword.Constant */ +html[data-theme="dark"] .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ +html[data-theme="dark"] .highlight .kn { color: #ff4689 } /* Keyword.Namespace */ +html[data-theme="dark"] .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ +html[data-theme="dark"] .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ +html[data-theme="dark"] .highlight .kt { color: #66d9ef } /* Keyword.Type */ +html[data-theme="dark"] .highlight .ld { color: #e6db74 } /* Literal.Date */ +html[data-theme="dark"] .highlight .m { color: #ae81ff } /* Literal.Number */ +html[data-theme="dark"] .highlight .s { color: #e6db74 } /* Literal.String */ +html[data-theme="dark"] .highlight .na { color: #a6e22e } /* Name.Attribute */ +html[data-theme="dark"] .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ +html[data-theme="dark"] .highlight .nc { color: #a6e22e } /* Name.Class */ +html[data-theme="dark"] .highlight .no { color: #66d9ef } /* Name.Constant */ +html[data-theme="dark"] .highlight .nd { color: #a6e22e } /* Name.Decorator */ +html[data-theme="dark"] .highlight .ni { color: #f8f8f2 } /* Name.Entity */ +html[data-theme="dark"] .highlight .ne { color: #a6e22e } /* Name.Exception */ +html[data-theme="dark"] .highlight .nf { color: #a6e22e } /* Name.Function */ +html[data-theme="dark"] .highlight .nl { color: #f8f8f2 } /* Name.Label */ +html[data-theme="dark"] .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ +html[data-theme="dark"] .highlight .nx { color: #a6e22e } /* Name.Other */ +html[data-theme="dark"] .highlight .py { color: #f8f8f2 } /* Name.Property */ +html[data-theme="dark"] .highlight .nt { color: #ff4689 } /* Name.Tag */ +html[data-theme="dark"] .highlight .nv { color: #f8f8f2 } /* Name.Variable */ +html[data-theme="dark"] .highlight .ow { color: #ff4689 } /* Operator.Word */ +html[data-theme="dark"] .highlight .pm { color: #f8f8f2 } /* Punctuation.Marker */ +html[data-theme="dark"] .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ +html[data-theme="dark"] .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ +html[data-theme="dark"] .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ +html[data-theme="dark"] .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ +html[data-theme="dark"] .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ +html[data-theme="dark"] .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ +html[data-theme="dark"] .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ +html[data-theme="dark"] .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ +html[data-theme="dark"] .highlight .sc { color: #e6db74 } /* Literal.String.Char */ +html[data-theme="dark"] .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ +html[data-theme="dark"] .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ +html[data-theme="dark"] .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ +html[data-theme="dark"] .highlight .se { color: #ae81ff } /* Literal.String.Escape */ +html[data-theme="dark"] .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ +html[data-theme="dark"] .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ +html[data-theme="dark"] .highlight .sx { color: #e6db74 } /* Literal.String.Other */ +html[data-theme="dark"] .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ +html[data-theme="dark"] .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ +html[data-theme="dark"] .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ +html[data-theme="dark"] .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ +html[data-theme="dark"] .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ +html[data-theme="dark"] .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ +html[data-theme="dark"] .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ +html[data-theme="dark"] .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ +html[data-theme="dark"] .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ +html[data-theme="dark"] .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/version/dev/_static/scripts/bootstrap.js b/version/dev/_static/scripts/bootstrap.js new file mode 100644 index 00000000..c8178deb --- /dev/null +++ b/version/dev/_static/scripts/bootstrap.js @@ -0,0 +1,3 @@ +/*! For license information please see bootstrap.js.LICENSE.txt */ +(()=>{"use strict";var t={d:(e,i)=>{for(var n in i)t.o(i,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:i[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{afterMain:()=>E,afterRead:()=>v,afterWrite:()=>C,applyStyles:()=>$,arrow:()=>J,auto:()=>a,basePlacements:()=>l,beforeMain:()=>y,beforeRead:()=>_,beforeWrite:()=>A,bottom:()=>s,clippingParents:()=>d,computeStyles:()=>it,createPopper:()=>Dt,createPopperBase:()=>St,createPopperLite:()=>$t,detectOverflow:()=>_t,end:()=>h,eventListeners:()=>st,flip:()=>bt,hide:()=>wt,left:()=>r,main:()=>w,modifierPhases:()=>O,offset:()=>Et,placements:()=>g,popper:()=>f,popperGenerator:()=>Lt,popperOffsets:()=>At,preventOverflow:()=>Tt,read:()=>b,reference:()=>p,right:()=>o,start:()=>c,top:()=>n,variationPlacements:()=>m,viewport:()=>u,write:()=>T});var i={};t.r(i),t.d(i,{Alert:()=>Oe,Button:()=>ke,Carousel:()=>li,Collapse:()=>Ei,Dropdown:()=>Ki,Modal:()=>Ln,Offcanvas:()=>Kn,Popover:()=>bs,ScrollSpy:()=>Ls,Tab:()=>Js,Toast:()=>po,Tooltip:()=>fs});var n="top",s="bottom",o="right",r="left",a="auto",l=[n,s,o,r],c="start",h="end",d="clippingParents",u="viewport",f="popper",p="reference",m=l.reduce((function(t,e){return t.concat([e+"-"+c,e+"-"+h])}),[]),g=[].concat(l,[a]).reduce((function(t,e){return t.concat([e,e+"-"+c,e+"-"+h])}),[]),_="beforeRead",b="read",v="afterRead",y="beforeMain",w="main",E="afterMain",A="beforeWrite",T="write",C="afterWrite",O=[_,b,v,y,w,E,A,T,C];function x(t){return t?(t.nodeName||"").toLowerCase():null}function k(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function L(t){return t instanceof k(t).Element||t instanceof Element}function S(t){return t instanceof k(t).HTMLElement||t instanceof HTMLElement}function D(t){return"undefined"!=typeof ShadowRoot&&(t instanceof k(t).ShadowRoot||t instanceof ShadowRoot)}const $={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];S(s)&&x(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});S(n)&&x(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function I(t){return t.split("-")[0]}var N=Math.max,P=Math.min,M=Math.round;function j(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function F(){return!/^((?!chrome|android).)*safari/i.test(j())}function H(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&S(t)&&(s=t.offsetWidth>0&&M(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&M(n.height)/t.offsetHeight||1);var r=(L(t)?k(t):window).visualViewport,a=!F()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function B(t){var e=H(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function W(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&D(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function z(t){return k(t).getComputedStyle(t)}function R(t){return["table","td","th"].indexOf(x(t))>=0}function q(t){return((L(t)?t.ownerDocument:t.document)||window.document).documentElement}function V(t){return"html"===x(t)?t:t.assignedSlot||t.parentNode||(D(t)?t.host:null)||q(t)}function Y(t){return S(t)&&"fixed"!==z(t).position?t.offsetParent:null}function K(t){for(var e=k(t),i=Y(t);i&&R(i)&&"static"===z(i).position;)i=Y(i);return i&&("html"===x(i)||"body"===x(i)&&"static"===z(i).position)?e:i||function(t){var e=/firefox/i.test(j());if(/Trident/i.test(j())&&S(t)&&"fixed"===z(t).position)return null;var i=V(t);for(D(i)&&(i=i.host);S(i)&&["html","body"].indexOf(x(i))<0;){var n=z(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Q(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function X(t,e,i){return N(t,P(e,i))}function U(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function G(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const J={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,a=t.name,c=t.options,h=i.elements.arrow,d=i.modifiersData.popperOffsets,u=I(i.placement),f=Q(u),p=[r,o].indexOf(u)>=0?"height":"width";if(h&&d){var m=function(t,e){return U("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:G(t,l))}(c.padding,i),g=B(h),_="y"===f?n:r,b="y"===f?s:o,v=i.rects.reference[p]+i.rects.reference[f]-d[f]-i.rects.popper[p],y=d[f]-i.rects.reference[f],w=K(h),E=w?"y"===f?w.clientHeight||0:w.clientWidth||0:0,A=v/2-y/2,T=m[_],C=E-g[p]-m[b],O=E/2-g[p]/2+A,x=X(T,O,C),k=f;i.modifiersData[a]=((e={})[k]=x,e.centerOffset=x-O,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&W(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Z(t){return t.split("-")[1]}var tt={top:"auto",right:"auto",bottom:"auto",left:"auto"};function et(t){var e,i=t.popper,a=t.popperRect,l=t.placement,c=t.variation,d=t.offsets,u=t.position,f=t.gpuAcceleration,p=t.adaptive,m=t.roundOffsets,g=t.isFixed,_=d.x,b=void 0===_?0:_,v=d.y,y=void 0===v?0:v,w="function"==typeof m?m({x:b,y}):{x:b,y};b=w.x,y=w.y;var E=d.hasOwnProperty("x"),A=d.hasOwnProperty("y"),T=r,C=n,O=window;if(p){var x=K(i),L="clientHeight",S="clientWidth";x===k(i)&&"static"!==z(x=q(i)).position&&"absolute"===u&&(L="scrollHeight",S="scrollWidth"),(l===n||(l===r||l===o)&&c===h)&&(C=s,y-=(g&&x===O&&O.visualViewport?O.visualViewport.height:x[L])-a.height,y*=f?1:-1),l!==r&&(l!==n&&l!==s||c!==h)||(T=o,b-=(g&&x===O&&O.visualViewport?O.visualViewport.width:x[S])-a.width,b*=f?1:-1)}var D,$=Object.assign({position:u},p&&tt),I=!0===m?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:M(i*s)/s||0,y:M(n*s)/s||0}}({x:b,y},k(i)):{x:b,y};return b=I.x,y=I.y,f?Object.assign({},$,((D={})[C]=A?"0":"",D[T]=E?"0":"",D.transform=(O.devicePixelRatio||1)<=1?"translate("+b+"px, "+y+"px)":"translate3d("+b+"px, "+y+"px, 0)",D)):Object.assign({},$,((e={})[C]=A?y+"px":"",e[T]=E?b+"px":"",e.transform="",e))}const it={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:I(e.placement),variation:Z(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,et(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,et(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var nt={passive:!0};const st={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=k(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,nt)})),a&&l.addEventListener("resize",i.update,nt),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,nt)})),a&&l.removeEventListener("resize",i.update,nt)}},data:{}};var ot={left:"right",right:"left",bottom:"top",top:"bottom"};function rt(t){return t.replace(/left|right|bottom|top/g,(function(t){return ot[t]}))}var at={start:"end",end:"start"};function lt(t){return t.replace(/start|end/g,(function(t){return at[t]}))}function ct(t){var e=k(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ht(t){return H(q(t)).left+ct(t).scrollLeft}function dt(t){var e=z(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function ut(t){return["html","body","#document"].indexOf(x(t))>=0?t.ownerDocument.body:S(t)&&dt(t)?t:ut(V(t))}function ft(t,e){var i;void 0===e&&(e=[]);var n=ut(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=k(n),r=s?[o].concat(o.visualViewport||[],dt(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ft(V(r)))}function pt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function mt(t,e,i){return e===u?pt(function(t,e){var i=k(t),n=q(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=F();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+ht(t),y:l}}(t,i)):L(e)?function(t,e){var i=H(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):pt(function(t){var e,i=q(t),n=ct(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=N(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=N(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ht(t),l=-n.scrollTop;return"rtl"===z(s||i).direction&&(a+=N(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(q(t)))}function gt(t){var e,i=t.reference,a=t.element,l=t.placement,d=l?I(l):null,u=l?Z(l):null,f=i.x+i.width/2-a.width/2,p=i.y+i.height/2-a.height/2;switch(d){case n:e={x:f,y:i.y-a.height};break;case s:e={x:f,y:i.y+i.height};break;case o:e={x:i.x+i.width,y:p};break;case r:e={x:i.x-a.width,y:p};break;default:e={x:i.x,y:i.y}}var m=d?Q(d):null;if(null!=m){var g="y"===m?"height":"width";switch(u){case c:e[m]=e[m]-(i[g]/2-a[g]/2);break;case h:e[m]=e[m]+(i[g]/2-a[g]/2)}}return e}function _t(t,e){void 0===e&&(e={});var i=e,r=i.placement,a=void 0===r?t.placement:r,c=i.strategy,h=void 0===c?t.strategy:c,m=i.boundary,g=void 0===m?d:m,_=i.rootBoundary,b=void 0===_?u:_,v=i.elementContext,y=void 0===v?f:v,w=i.altBoundary,E=void 0!==w&&w,A=i.padding,T=void 0===A?0:A,C=U("number"!=typeof T?T:G(T,l)),O=y===f?p:f,k=t.rects.popper,D=t.elements[E?O:y],$=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ft(V(t)),i=["absolute","fixed"].indexOf(z(t).position)>=0&&S(t)?K(t):t;return L(i)?e.filter((function(t){return L(t)&&W(t,i)&&"body"!==x(t)})):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce((function(e,i){var s=mt(t,i,n);return e.top=N(s.top,e.top),e.right=P(s.right,e.right),e.bottom=P(s.bottom,e.bottom),e.left=N(s.left,e.left),e}),mt(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(L(D)?D:D.contextElement||q(t.elements.popper),g,b,h),I=H(t.elements.reference),M=gt({reference:I,element:k,strategy:"absolute",placement:a}),j=pt(Object.assign({},k,M)),F=y===f?j:I,B={top:$.top-F.top+C.top,bottom:F.bottom-$.bottom+C.bottom,left:$.left-F.left+C.left,right:F.right-$.right+C.right},R=t.modifiersData.offset;if(y===f&&R){var Y=R[a];Object.keys(B).forEach((function(t){var e=[o,s].indexOf(t)>=0?1:-1,i=[n,s].indexOf(t)>=0?"y":"x";B[t]+=Y[i]*e}))}return B}const bt={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,h=t.name;if(!e.modifiersData[h]._skip){for(var d=i.mainAxis,u=void 0===d||d,f=i.altAxis,p=void 0===f||f,_=i.fallbackPlacements,b=i.padding,v=i.boundary,y=i.rootBoundary,w=i.altBoundary,E=i.flipVariations,A=void 0===E||E,T=i.allowedAutoPlacements,C=e.options.placement,O=I(C),x=_||(O!==C&&A?function(t){if(I(t)===a)return[];var e=rt(t);return[lt(t),e,lt(e)]}(C):[rt(C)]),k=[C].concat(x).reduce((function(t,i){return t.concat(I(i)===a?function(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,c=i.allowedAutoPlacements,h=void 0===c?g:c,d=Z(n),u=d?a?m:m.filter((function(t){return Z(t)===d})):l,f=u.filter((function(t){return h.indexOf(t)>=0}));0===f.length&&(f=u);var p=f.reduce((function(e,i){return e[i]=_t(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[I(i)],e}),{});return Object.keys(p).sort((function(t,e){return p[t]-p[e]}))}(e,{placement:i,boundary:v,rootBoundary:y,padding:b,flipVariations:A,allowedAutoPlacements:T}):i)}),[]),L=e.rects.reference,S=e.rects.popper,D=new Map,$=!0,N=k[0],P=0;P=0,B=H?"width":"height",W=_t(e,{placement:M,boundary:v,rootBoundary:y,altBoundary:w,padding:b}),z=H?F?o:r:F?s:n;L[B]>S[B]&&(z=rt(z));var R=rt(z),q=[];if(u&&q.push(W[j]<=0),p&&q.push(W[z]<=0,W[R]<=0),q.every((function(t){return t}))){N=M,$=!1;break}D.set(M,q)}if($)for(var V=function(t){var e=k.find((function(e){var i=D.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return N=e,"break"},Y=A?3:1;Y>0&&"break"!==V(Y);Y--);e.placement!==N&&(e.modifiersData[h]._skip=!0,e.placement=N,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function vt(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function yt(t){return[n,o,s,r].some((function(e){return t[e]>=0}))}const wt={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=_t(e,{elementContext:"reference"}),a=_t(e,{altBoundary:!0}),l=vt(r,n),c=vt(a,s,o),h=yt(l),d=yt(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Et={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,s=t.name,a=i.offset,l=void 0===a?[0,0]:a,c=g.reduce((function(t,i){return t[i]=function(t,e,i){var s=I(t),a=[r,n].indexOf(s)>=0?-1:1,l="function"==typeof i?i(Object.assign({},e,{placement:t})):i,c=l[0],h=l[1];return c=c||0,h=(h||0)*a,[r,o].indexOf(s)>=0?{x:h,y:c}:{x:c,y:h}}(i,e.rects,l),t}),{}),h=c[e.placement],d=h.x,u=h.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=d,e.modifiersData.popperOffsets.y+=u),e.modifiersData[s]=c}},At={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=gt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},Tt={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,a=t.name,l=i.mainAxis,h=void 0===l||l,d=i.altAxis,u=void 0!==d&&d,f=i.boundary,p=i.rootBoundary,m=i.altBoundary,g=i.padding,_=i.tether,b=void 0===_||_,v=i.tetherOffset,y=void 0===v?0:v,w=_t(e,{boundary:f,rootBoundary:p,padding:g,altBoundary:m}),E=I(e.placement),A=Z(e.placement),T=!A,C=Q(E),O="x"===C?"y":"x",x=e.modifiersData.popperOffsets,k=e.rects.reference,L=e.rects.popper,S="function"==typeof y?y(Object.assign({},e.rects,{placement:e.placement})):y,D="number"==typeof S?{mainAxis:S,altAxis:S}:Object.assign({mainAxis:0,altAxis:0},S),$=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,M={x:0,y:0};if(x){if(h){var j,F="y"===C?n:r,H="y"===C?s:o,W="y"===C?"height":"width",z=x[C],R=z+w[F],q=z-w[H],V=b?-L[W]/2:0,Y=A===c?k[W]:L[W],U=A===c?-L[W]:-k[W],G=e.elements.arrow,J=b&&G?B(G):{width:0,height:0},tt=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},et=tt[F],it=tt[H],nt=X(0,k[W],J[W]),st=T?k[W]/2-V-nt-et-D.mainAxis:Y-nt-et-D.mainAxis,ot=T?-k[W]/2+V+nt+it+D.mainAxis:U+nt+it+D.mainAxis,rt=e.elements.arrow&&K(e.elements.arrow),at=rt?"y"===C?rt.clientTop||0:rt.clientLeft||0:0,lt=null!=(j=null==$?void 0:$[C])?j:0,ct=z+ot-lt,ht=X(b?P(R,z+st-lt-at):R,z,b?N(q,ct):q);x[C]=ht,M[C]=ht-z}if(u){var dt,ut="x"===C?n:r,ft="x"===C?s:o,pt=x[O],mt="y"===O?"height":"width",gt=pt+w[ut],bt=pt-w[ft],vt=-1!==[n,r].indexOf(E),yt=null!=(dt=null==$?void 0:$[O])?dt:0,wt=vt?gt:pt-k[mt]-L[mt]-yt+D.altAxis,Et=vt?pt+k[mt]+L[mt]-yt-D.altAxis:bt,At=b&&vt?function(t,e,i){var n=X(t,e,i);return n>i?i:n}(wt,pt,Et):X(b?wt:gt,pt,b?Et:bt);x[O]=At,M[O]=At-pt}e.modifiersData[a]=M}},requiresIfExists:["offset"]};function Ct(t,e,i){void 0===i&&(i=!1);var n,s,o=S(e),r=S(e)&&function(t){var e=t.getBoundingClientRect(),i=M(e.width)/t.offsetWidth||1,n=M(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=q(e),l=H(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==x(e)||dt(a))&&(c=(n=e)!==k(n)&&S(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:ct(n)),S(e)?((h=H(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=ht(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function Ot(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var xt={placement:"bottom",modifiers:[],strategy:"absolute"};function kt(){for(var t=arguments.length,e=new Array(t),i=0;iIt.has(t)&&It.get(t).get(e)||null,remove(t,e){if(!It.has(t))return;const i=It.get(t);i.delete(e),0===i.size&&It.delete(t)}},Pt="transitionend",Mt=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),jt=t=>{t.dispatchEvent(new Event(Pt))},Ft=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),Ht=t=>Ft(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(Mt(t)):null,Bt=t=>{if(!Ft(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},Wt=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),zt=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?zt(t.parentNode):null},Rt=()=>{},qt=t=>{t.offsetHeight},Vt=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,Yt=[],Kt=()=>"rtl"===document.documentElement.dir,Qt=t=>{var e;e=()=>{const e=Vt();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(Yt.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of Yt)t()})),Yt.push(e)):e()},Xt=(t,e=[],i=t)=>"function"==typeof t?t(...e):i,Ut=(t,e,i=!0)=>{if(!i)return void Xt(t);const n=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let s=!1;const o=({target:i})=>{i===e&&(s=!0,e.removeEventListener(Pt,o),Xt(t))};e.addEventListener(Pt,o),setTimeout((()=>{s||jt(e)}),n)},Gt=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},Jt=/[^.]*(?=\..*)\.|.*/,Zt=/\..*/,te=/::\d+$/,ee={};let ie=1;const ne={mouseenter:"mouseover",mouseleave:"mouseout"},se=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function oe(t,e){return e&&`${e}::${ie++}`||t.uidEvent||ie++}function re(t){const e=oe(t);return t.uidEvent=e,ee[e]=ee[e]||{},ee[e]}function ae(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function le(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=ue(t);return se.has(o)||(o=t),[n,s,o]}function ce(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=le(e,i,n);if(e in ne){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=re(t),c=l[a]||(l[a]={}),h=ae(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=oe(r,e.replace(Jt,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return pe(s,{delegateTarget:r}),n.oneOff&&fe.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return pe(n,{delegateTarget:t}),i.oneOff&&fe.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function he(t,e,i,n,s){const o=ae(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function de(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&he(t,e,i,r.callable,r.delegationSelector)}function ue(t){return t=t.replace(Zt,""),ne[t]||t}const fe={on(t,e,i,n){ce(t,e,i,n,!1)},one(t,e,i,n){ce(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=le(e,i,n),a=r!==e,l=re(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))de(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(te,"");a&&!e.includes(s)||he(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;he(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=Vt();let s=null,o=!0,r=!0,a=!1;e!==ue(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=pe(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function pe(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function me(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function ge(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const _e={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${ge(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${ge(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=me(t.dataset[n])}return e},getDataAttribute:(t,e)=>me(t.getAttribute(`data-bs-${ge(e)}`))};class be{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=Ft(e)?_e.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...Ft(e)?_e.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[n,s]of Object.entries(e)){const e=t[n],o=Ft(e)?"element":null==(i=e)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${o}" but expected type "${s}".`)}var i}}class ve extends be{constructor(t,e){super(),(t=Ht(t))&&(this._element=t,this._config=this._getConfig(e),Nt.set(this._element,this.constructor.DATA_KEY,this))}dispose(){Nt.remove(this._element,this.constructor.DATA_KEY),fe.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){Ut(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return Nt.get(Ht(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.3"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const ye=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map((t=>Mt(t))).join(","):null},we={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!Wt(t)&&Bt(t)))},getSelectorFromElement(t){const e=ye(t);return e&&we.findOne(e)?e:null},getElementFromSelector(t){const e=ye(t);return e?we.findOne(e):null},getMultipleElementsFromSelector(t){const e=ye(t);return e?we.find(e):[]}},Ee=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;fe.on(document,i,`[data-bs-dismiss="${n}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),Wt(this))return;const s=we.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()}))},Ae=".bs.alert",Te=`close${Ae}`,Ce=`closed${Ae}`;class Oe extends ve{static get NAME(){return"alert"}close(){if(fe.trigger(this._element,Te).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),fe.trigger(this._element,Ce),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Oe.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}Ee(Oe,"close"),Qt(Oe);const xe='[data-bs-toggle="button"]';class ke extends ve{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=ke.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}fe.on(document,"click.bs.button.data-api",xe,(t=>{t.preventDefault();const e=t.target.closest(xe);ke.getOrCreateInstance(e).toggle()})),Qt(ke);const Le=".bs.swipe",Se=`touchstart${Le}`,De=`touchmove${Le}`,$e=`touchend${Le}`,Ie=`pointerdown${Le}`,Ne=`pointerup${Le}`,Pe={endCallback:null,leftCallback:null,rightCallback:null},Me={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class je extends be{constructor(t,e){super(),this._element=t,t&&je.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return Pe}static get DefaultType(){return Me}static get NAME(){return"swipe"}dispose(){fe.off(this._element,Le)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),Xt(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&Xt(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(fe.on(this._element,Ie,(t=>this._start(t))),fe.on(this._element,Ne,(t=>this._end(t))),this._element.classList.add("pointer-event")):(fe.on(this._element,Se,(t=>this._start(t))),fe.on(this._element,De,(t=>this._move(t))),fe.on(this._element,$e,(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const Fe=".bs.carousel",He=".data-api",Be="ArrowLeft",We="ArrowRight",ze="next",Re="prev",qe="left",Ve="right",Ye=`slide${Fe}`,Ke=`slid${Fe}`,Qe=`keydown${Fe}`,Xe=`mouseenter${Fe}`,Ue=`mouseleave${Fe}`,Ge=`dragstart${Fe}`,Je=`load${Fe}${He}`,Ze=`click${Fe}${He}`,ti="carousel",ei="active",ii=".active",ni=".carousel-item",si=ii+ni,oi={[Be]:Ve,[We]:qe},ri={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},ai={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class li extends ve{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=we.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===ti&&this.cycle()}static get Default(){return ri}static get DefaultType(){return ai}static get NAME(){return"carousel"}next(){this._slide(ze)}nextWhenVisible(){!document.hidden&&Bt(this._element)&&this.next()}prev(){this._slide(Re)}pause(){this._isSliding&&jt(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?fe.one(this._element,Ke,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void fe.one(this._element,Ke,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ze:Re;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&fe.on(this._element,Qe,(t=>this._keydown(t))),"hover"===this._config.pause&&(fe.on(this._element,Xe,(()=>this.pause())),fe.on(this._element,Ue,(()=>this._maybeEnableCycle()))),this._config.touch&&je.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of we.find(".carousel-item img",this._element))fe.on(t,Ge,(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(qe)),rightCallback:()=>this._slide(this._directionToOrder(Ve)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new je(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=oi[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=we.findOne(ii,this._indicatorsElement);e.classList.remove(ei),e.removeAttribute("aria-current");const i=we.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(ei),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ze,s=e||Gt(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>fe.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(Ye).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),qt(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(ei),i.classList.remove(ei,c,l),this._isSliding=!1,r(Ke)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return we.findOne(si,this._element)}_getItems(){return we.find(ni,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return Kt()?t===qe?Re:ze:t===qe?ze:Re}_orderToDirection(t){return Kt()?t===Re?qe:Ve:t===Re?Ve:qe}static jQueryInterface(t){return this.each((function(){const e=li.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}fe.on(document,Ze,"[data-bs-slide], [data-bs-slide-to]",(function(t){const e=we.getElementFromSelector(this);if(!e||!e.classList.contains(ti))return;t.preventDefault();const i=li.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===_e.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),fe.on(window,Je,(()=>{const t=we.find('[data-bs-ride="carousel"]');for(const e of t)li.getOrCreateInstance(e)})),Qt(li);const ci=".bs.collapse",hi=`show${ci}`,di=`shown${ci}`,ui=`hide${ci}`,fi=`hidden${ci}`,pi=`click${ci}.data-api`,mi="show",gi="collapse",_i="collapsing",bi=`:scope .${gi} .${gi}`,vi='[data-bs-toggle="collapse"]',yi={parent:null,toggle:!0},wi={parent:"(null|element)",toggle:"boolean"};class Ei extends ve{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=we.find(vi);for(const t of i){const e=we.getSelectorFromElement(t),i=we.find(e).filter((t=>t===this._element));null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return yi}static get DefaultType(){return wi}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Ei.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(fe.trigger(this._element,hi).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(gi),this._element.classList.add(_i),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(_i),this._element.classList.add(gi,mi),this._element.style[e]="",fe.trigger(this._element,di)}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(fe.trigger(this._element,ui).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,qt(this._element),this._element.classList.add(_i),this._element.classList.remove(gi,mi);for(const t of this._triggerArray){const e=we.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(_i),this._element.classList.add(gi),fe.trigger(this._element,fi)}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(mi)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=Ht(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(vi);for(const e of t){const t=we.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=we.find(bi,this._config.parent);return we.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=Ei.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}fe.on(document,pi,vi,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of we.getMultipleElementsFromSelector(this))Ei.getOrCreateInstance(t,{toggle:!1}).toggle()})),Qt(Ei);const Ai="dropdown",Ti=".bs.dropdown",Ci=".data-api",Oi="ArrowUp",xi="ArrowDown",ki=`hide${Ti}`,Li=`hidden${Ti}`,Si=`show${Ti}`,Di=`shown${Ti}`,$i=`click${Ti}${Ci}`,Ii=`keydown${Ti}${Ci}`,Ni=`keyup${Ti}${Ci}`,Pi="show",Mi='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',ji=`${Mi}.${Pi}`,Fi=".dropdown-menu",Hi=Kt()?"top-end":"top-start",Bi=Kt()?"top-start":"top-end",Wi=Kt()?"bottom-end":"bottom-start",zi=Kt()?"bottom-start":"bottom-end",Ri=Kt()?"left-start":"right-start",qi=Kt()?"right-start":"left-start",Vi={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},Yi={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class Ki extends ve{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=we.next(this._element,Fi)[0]||we.prev(this._element,Fi)[0]||we.findOne(Fi,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return Vi}static get DefaultType(){return Yi}static get NAME(){return Ai}toggle(){return this._isShown()?this.hide():this.show()}show(){if(Wt(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!fe.trigger(this._element,Si,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Rt);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Pi),this._element.classList.add(Pi),fe.trigger(this._element,Di,t)}}hide(){if(Wt(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!fe.trigger(this._element,ki,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Rt);this._popper&&this._popper.destroy(),this._menu.classList.remove(Pi),this._element.classList.remove(Pi),this._element.setAttribute("aria-expanded","false"),_e.removeDataAttribute(this._menu,"popper"),fe.trigger(this._element,Li,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!Ft(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ai.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===e)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let t=this._element;"parent"===this._config.reference?t=this._parent:Ft(this._config.reference)?t=Ht(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const i=this._getPopperConfig();this._popper=Dt(t,this._menu,i)}_isShown(){return this._menu.classList.contains(Pi)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return Ri;if(t.classList.contains("dropstart"))return qi;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Bi:Hi:e?zi:Wi}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(_e.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...Xt(this._config.popperConfig,[t])}}_selectMenuItem({key:t,target:e}){const i=we.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>Bt(t)));i.length&&Gt(i,e,t===xi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Ki.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=we.find(ji);for(const i of e){const e=Ki.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Oi,xi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(Mi)?this:we.prev(this,Mi)[0]||we.next(this,Mi)[0]||we.findOne(Mi,t.delegateTarget.parentNode),o=Ki.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}fe.on(document,Ii,Mi,Ki.dataApiKeydownHandler),fe.on(document,Ii,Fi,Ki.dataApiKeydownHandler),fe.on(document,$i,Ki.clearMenus),fe.on(document,Ni,Ki.clearMenus),fe.on(document,$i,Mi,(function(t){t.preventDefault(),Ki.getOrCreateInstance(this).toggle()})),Qt(Ki);const Qi="backdrop",Xi="show",Ui=`mousedown.bs.${Qi}`,Gi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ji={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Zi extends be{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Gi}static get DefaultType(){return Ji}static get NAME(){return Qi}show(t){if(!this._config.isVisible)return void Xt(t);this._append();const e=this._getElement();this._config.isAnimated&&qt(e),e.classList.add(Xi),this._emulateAnimation((()=>{Xt(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(Xi),this._emulateAnimation((()=>{this.dispose(),Xt(t)}))):Xt(t)}dispose(){this._isAppended&&(fe.off(this._element,Ui),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=Ht(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),fe.on(t,Ui,(()=>{Xt(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){Ut(t,this._getElement(),this._config.isAnimated)}}const tn=".bs.focustrap",en=`focusin${tn}`,nn=`keydown.tab${tn}`,sn="backward",on={autofocus:!0,trapElement:null},rn={autofocus:"boolean",trapElement:"element"};class an extends be{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return on}static get DefaultType(){return rn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),fe.off(document,tn),fe.on(document,en,(t=>this._handleFocusin(t))),fe.on(document,nn,(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,fe.off(document,tn))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=we.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===sn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?sn:"forward")}}const ln=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",cn=".sticky-top",hn="padding-right",dn="margin-right";class un{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,hn,(e=>e+t)),this._setElementAttributes(ln,hn,(e=>e+t)),this._setElementAttributes(cn,dn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,hn),this._resetElementAttributes(ln,hn),this._resetElementAttributes(cn,dn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&_e.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=_e.getDataAttribute(t,e);null!==i?(_e.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(Ft(t))e(t);else for(const i of we.find(t,this._element))e(i)}}const fn=".bs.modal",pn=`hide${fn}`,mn=`hidePrevented${fn}`,gn=`hidden${fn}`,_n=`show${fn}`,bn=`shown${fn}`,vn=`resize${fn}`,yn=`click.dismiss${fn}`,wn=`mousedown.dismiss${fn}`,En=`keydown.dismiss${fn}`,An=`click${fn}.data-api`,Tn="modal-open",Cn="show",On="modal-static",xn={backdrop:!0,focus:!0,keyboard:!0},kn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ln extends ve{constructor(t,e){super(t,e),this._dialog=we.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new un,this._addEventListeners()}static get Default(){return xn}static get DefaultType(){return kn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||fe.trigger(this._element,_n,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Tn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(fe.trigger(this._element,pn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Cn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){fe.off(window,fn),fe.off(this._dialog,fn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Zi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new an({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=we.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),qt(this._element),this._element.classList.add(Cn),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,fe.trigger(this._element,bn,{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){fe.on(this._element,En,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),fe.on(window,vn,(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),fe.on(this._element,wn,(t=>{fe.one(this._element,yn,(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Tn),this._resetAdjustments(),this._scrollBar.reset(),fe.trigger(this._element,gn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(fe.trigger(this._element,mn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(On)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(On),this._queueCallback((()=>{this._element.classList.remove(On),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=Kt()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=Kt()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Ln.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}fe.on(document,An,'[data-bs-toggle="modal"]',(function(t){const e=we.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),fe.one(e,_n,(t=>{t.defaultPrevented||fe.one(e,gn,(()=>{Bt(this)&&this.focus()}))}));const i=we.findOne(".modal.show");i&&Ln.getInstance(i).hide(),Ln.getOrCreateInstance(e).toggle(this)})),Ee(Ln),Qt(Ln);const Sn=".bs.offcanvas",Dn=".data-api",$n=`load${Sn}${Dn}`,In="show",Nn="showing",Pn="hiding",Mn=".offcanvas.show",jn=`show${Sn}`,Fn=`shown${Sn}`,Hn=`hide${Sn}`,Bn=`hidePrevented${Sn}`,Wn=`hidden${Sn}`,zn=`resize${Sn}`,Rn=`click${Sn}${Dn}`,qn=`keydown.dismiss${Sn}`,Vn={backdrop:!0,keyboard:!0,scroll:!1},Yn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends ve{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return Vn}static get DefaultType(){return Yn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||fe.trigger(this._element,jn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new un).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Nn),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(In),this._element.classList.remove(Nn),fe.trigger(this._element,Fn,{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(fe.trigger(this._element,Hn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Pn),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(In,Pn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new un).reset(),fe.trigger(this._element,Wn)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Zi({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():fe.trigger(this._element,Bn)}:null})}_initializeFocusTrap(){return new an({trapElement:this._element})}_addEventListeners(){fe.on(this._element,qn,(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():fe.trigger(this._element,Bn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}fe.on(document,Rn,'[data-bs-toggle="offcanvas"]',(function(t){const e=we.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),Wt(this))return;fe.one(e,Wn,(()=>{Bt(this)&&this.focus()}));const i=we.findOne(Mn);i&&i!==e&&Kn.getInstance(i).hide(),Kn.getOrCreateInstance(e).toggle(this)})),fe.on(window,$n,(()=>{for(const t of we.find(Mn))Kn.getOrCreateInstance(t).show()})),fe.on(window,zn,(()=>{for(const t of we.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),Ee(Kn),Qt(Kn);const Qn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Xn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Un=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Gn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Xn.has(i)||Boolean(Un.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Jn={allowList:Qn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Zn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ts={entry:"(string|element|function|null)",selector:"(string|element)"};class es extends be{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Jn}static get DefaultType(){return Zn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},ts)}_setContent(t,e,i){const n=we.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?Ft(e)?this._putElementInTemplate(Ht(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Gn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return Xt(t,[this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const is=new Set(["sanitize","allowList","sanitizeFn"]),ns="fade",ss="show",os=".tooltip-inner",rs=".modal",as="hide.bs.modal",ls="hover",cs="focus",hs={AUTO:"auto",TOP:"top",RIGHT:Kt()?"left":"right",BOTTOM:"bottom",LEFT:Kt()?"right":"left"},ds={allowList:Qn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},us={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class fs extends ve{constructor(t,i){if(void 0===e)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,i),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return ds}static get DefaultType(){return us}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),fe.off(this._element.closest(rs),as,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=fe.trigger(this._element,this.constructor.eventName("show")),e=(zt(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),fe.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Rt);this._queueCallback((()=>{fe.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(this._isShown()&&!fe.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Rt);this._activeTrigger.click=!1,this._activeTrigger[cs]=!1,this._activeTrigger[ls]=!1,this._isHovered=null,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),fe.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ns,ss),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ns),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new es({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[os]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ns)}_isShown(){return this.tip&&this.tip.classList.contains(ss)}_createPopper(t){const e=Xt(this._config.placement,[this,t,this._element]),i=hs[e.toUpperCase()];return Dt(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return Xt(t,[this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...Xt(this._config.popperConfig,[e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)fe.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{this._initializeOnDelegatedTarget(t).toggle()}));else if("manual"!==e){const t=e===ls?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ls?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");fe.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?cs:ls]=!0,e._enter()})),fe.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?cs:ls]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},fe.on(this._element.closest(rs),as,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=_e.getDataAttributes(this._element);for(const t of Object.keys(e))is.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:Ht(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=fs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Qt(fs);const ps=".popover-header",ms=".popover-body",gs={...fs.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},_s={...fs.DefaultType,content:"(null|string|element|function)"};class bs extends fs{static get Default(){return gs}static get DefaultType(){return _s}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[ps]:this._getTitle(),[ms]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=bs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Qt(bs);const vs=".bs.scrollspy",ys=`activate${vs}`,ws=`click${vs}`,Es=`load${vs}.data-api`,As="active",Ts="[href]",Cs=".nav-link",Os=`${Cs}, .nav-item > ${Cs}, .list-group-item`,xs={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},ks={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Ls extends ve{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return xs}static get DefaultType(){return ks}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=Ht(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(fe.off(this._config.target,ws),fe.on(this._config.target,ws,Ts,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=we.find(Ts,this._config.target);for(const e of t){if(!e.hash||Wt(e))continue;const t=we.findOne(decodeURI(e.hash),this._element);Bt(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(As),this._activateParents(t),fe.trigger(this._element,ys,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))we.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(As);else for(const e of we.parents(t,".nav, .list-group"))for(const t of we.prev(e,Os))t.classList.add(As)}_clearActiveClass(t){t.classList.remove(As);const e=we.find(`${Ts}.${As}`,t);for(const t of e)t.classList.remove(As)}static jQueryInterface(t){return this.each((function(){const e=Ls.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}fe.on(window,Es,(()=>{for(const t of we.find('[data-bs-spy="scroll"]'))Ls.getOrCreateInstance(t)})),Qt(Ls);const Ss=".bs.tab",Ds=`hide${Ss}`,$s=`hidden${Ss}`,Is=`show${Ss}`,Ns=`shown${Ss}`,Ps=`click${Ss}`,Ms=`keydown${Ss}`,js=`load${Ss}`,Fs="ArrowLeft",Hs="ArrowRight",Bs="ArrowUp",Ws="ArrowDown",zs="Home",Rs="End",qs="active",Vs="fade",Ys="show",Ks=".dropdown-toggle",Qs=`:not(${Ks})`,Xs='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Us=`.nav-link${Qs}, .list-group-item${Qs}, [role="tab"]${Qs}, ${Xs}`,Gs=`.${qs}[data-bs-toggle="tab"], .${qs}[data-bs-toggle="pill"], .${qs}[data-bs-toggle="list"]`;class Js extends ve{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),fe.on(this._element,Ms,(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?fe.trigger(e,Ds,{relatedTarget:t}):null;fe.trigger(t,Is,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(qs),this._activate(we.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),fe.trigger(t,Ns,{relatedTarget:e})):t.classList.add(Ys)}),t,t.classList.contains(Vs)))}_deactivate(t,e){t&&(t.classList.remove(qs),t.blur(),this._deactivate(we.getElementFromSelector(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),fe.trigger(t,$s,{relatedTarget:e})):t.classList.remove(Ys)}),t,t.classList.contains(Vs)))}_keydown(t){if(![Fs,Hs,Bs,Ws,zs,Rs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!Wt(t)));let i;if([zs,Rs].includes(t.key))i=e[t.key===zs?0:e.length-1];else{const n=[Hs,Ws].includes(t.key);i=Gt(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Js.getOrCreateInstance(i).show())}_getChildren(){return we.find(Us,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=we.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=we.findOne(t,i);s&&s.classList.toggle(n,e)};n(Ks,qs),n(".dropdown-menu",Ys),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(qs)}_getInnerElement(t){return t.matches(Us)?t:we.findOne(Us,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=Js.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}fe.on(document,Ps,Xs,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),Wt(this)||Js.getOrCreateInstance(this).show()})),fe.on(window,js,(()=>{for(const t of we.find(Gs))Js.getOrCreateInstance(t)})),Qt(Js);const Zs=".bs.toast",to=`mouseover${Zs}`,eo=`mouseout${Zs}`,io=`focusin${Zs}`,no=`focusout${Zs}`,so=`hide${Zs}`,oo=`hidden${Zs}`,ro=`show${Zs}`,ao=`shown${Zs}`,lo="hide",co="show",ho="showing",uo={animation:"boolean",autohide:"boolean",delay:"number"},fo={animation:!0,autohide:!0,delay:5e3};class po extends ve{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return fo}static get DefaultType(){return uo}static get NAME(){return"toast"}show(){fe.trigger(this._element,ro).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(lo),qt(this._element),this._element.classList.add(co,ho),this._queueCallback((()=>{this._element.classList.remove(ho),fe.trigger(this._element,ao),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(fe.trigger(this._element,so).defaultPrevented||(this._element.classList.add(ho),this._queueCallback((()=>{this._element.classList.add(lo),this._element.classList.remove(ho,co),fe.trigger(this._element,oo)}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(co),super.dispose()}isShown(){return this._element.classList.contains(co)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){fe.on(this._element,to,(t=>this._onInteraction(t,!0))),fe.on(this._element,eo,(t=>this._onInteraction(t,!1))),fe.on(this._element,io,(t=>this._onInteraction(t,!0))),fe.on(this._element,no,(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=po.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}function mo(t){"loading"!=document.readyState?t():document.addEventListener("DOMContentLoaded",t)}Ee(po),Qt(po),mo((function(){[].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')).map((function(t){return new fs(t,{delay:{show:500,hide:100}})}))})),mo((function(){document.getElementById("pst-back-to-top").addEventListener("click",(function(){document.body.scrollTop=0,document.documentElement.scrollTop=0}))})),mo((function(){var t=document.getElementById("pst-back-to-top"),e=document.getElementsByClassName("bd-header")[0].getBoundingClientRect();window.addEventListener("scroll",(function(){this.oldScroll>this.scrollY&&this.scrollY>e.bottom?t.style.display="block":t.style.display="none",this.oldScroll=this.scrollY}))})),window.bootstrap=i})(); +//# sourceMappingURL=bootstrap.js.map \ No newline at end of file diff --git a/version/dev/_static/scripts/bootstrap.js.LICENSE.txt b/version/dev/_static/scripts/bootstrap.js.LICENSE.txt new file mode 100644 index 00000000..28755c2c --- /dev/null +++ b/version/dev/_static/scripts/bootstrap.js.LICENSE.txt @@ -0,0 +1,5 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ diff --git a/version/dev/_static/scripts/bootstrap.js.map b/version/dev/_static/scripts/bootstrap.js.map new file mode 100644 index 00000000..e9e81589 --- /dev/null +++ b/version/dev/_static/scripts/bootstrap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/bootstrap.js","mappings":"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","sources":["webpack://pydata_sphinx_theme/webpack/bootstrap","webpack://pydata_sphinx_theme/webpack/runtime/define property getters","webpack://pydata_sphinx_theme/webpack/runtime/hasOwnProperty shorthand","webpack://pydata_sphinx_theme/webpack/runtime/make namespace object","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/enums.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/applyStyles.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getBasePlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/math.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/userAgent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/contains.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/within.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/expandToHashMap.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/arrow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getVariation.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/computeStyles.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/eventListeners.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/rectToClientRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/computeOffsets.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/detectOverflow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/flip.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/hide.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/offset.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/getAltAxis.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/orderModifiers.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/createPopper.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/debounce.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/utils/mergeByName.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/popper.js","webpack://pydata_sphinx_theme/./node_modules/@popperjs/core/lib/popper-lite.js","webpack://pydata_sphinx_theme/./node_modules/bootstrap/dist/js/bootstrap.esm.js","webpack://pydata_sphinx_theme/./src/pydata_sphinx_theme/assets/scripts/mixin.js","webpack://pydata_sphinx_theme/./src/pydata_sphinx_theme/assets/scripts/bootstrap.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}","import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}","import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on \n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `` and `` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","/*!\n * Bootstrap v5.3.3 (https://getbootstrap.com/)\n * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\nimport * as Popper from '@popperjs/core';\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map();\nconst Data = {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map());\n }\n const instanceMap = elementMap.get(element);\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);\n return;\n }\n instanceMap.set(key, instance);\n },\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null;\n }\n return null;\n },\n remove(element, key) {\n if (!elementMap.has(element)) {\n return;\n }\n const instanceMap = elementMap.get(element);\n instanceMap.delete(key);\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element);\n }\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1000000;\nconst MILLISECONDS_MULTIPLIER = 1000;\nconst TRANSITION_END = 'transitionend';\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`);\n }\n return selector;\n};\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`;\n }\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase();\n};\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID);\n } while (document.getElementById(prefix));\n return prefix;\n};\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0;\n }\n\n // Get transition-duration of the element\n let {\n transitionDuration,\n transitionDelay\n } = window.getComputedStyle(element);\n const floatTransitionDuration = Number.parseFloat(transitionDuration);\n const floatTransitionDelay = Number.parseFloat(transitionDelay);\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0;\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0];\n transitionDelay = transitionDelay.split(',')[0];\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n};\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END));\n};\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false;\n }\n if (typeof object.jquery !== 'undefined') {\n object = object[0];\n }\n return typeof object.nodeType !== 'undefined';\n};\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object;\n }\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object));\n }\n return null;\n};\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false;\n }\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])');\n if (!closedDetails) {\n return elementIsVisible;\n }\n if (closedDetails !== element) {\n const summary = element.closest('summary');\n if (summary && summary.parentNode !== closedDetails) {\n return false;\n }\n if (summary === null) {\n return false;\n }\n }\n return elementIsVisible;\n};\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true;\n }\n if (element.classList.contains('disabled')) {\n return true;\n }\n if (typeof element.disabled !== 'undefined') {\n return element.disabled;\n }\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';\n};\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null;\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n if (element instanceof ShadowRoot) {\n return element;\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null;\n }\n return findShadowRoot(element.parentNode);\n};\nconst noop = () => {};\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight; // eslint-disable-line no-unused-expressions\n};\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery;\n }\n return null;\n};\nconst DOMContentLoadedCallbacks = [];\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback();\n }\n });\n }\n DOMContentLoadedCallbacks.push(callback);\n } else {\n callback();\n }\n};\nconst isRTL = () => document.documentElement.dir === 'rtl';\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery();\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME;\n const JQUERY_NO_CONFLICT = $.fn[name];\n $.fn[name] = plugin.jQueryInterface;\n $.fn[name].Constructor = plugin;\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT;\n return plugin.jQueryInterface;\n };\n }\n });\n};\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue;\n};\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback);\n return;\n }\n const durationPadding = 5;\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding;\n let called = false;\n const handler = ({\n target\n }) => {\n if (target !== transitionElement) {\n return;\n }\n called = true;\n transitionElement.removeEventListener(TRANSITION_END, handler);\n execute(callback);\n };\n transitionElement.addEventListener(TRANSITION_END, handler);\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement);\n }\n }, emulatedDuration);\n};\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length;\n let index = list.indexOf(activeElement);\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0];\n }\n index += shouldGetNext ? 1 : -1;\n if (isCycleAllowed) {\n index = (index + listLength) % listLength;\n }\n return list[Math.max(0, Math.min(index, listLength - 1))];\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/;\nconst stripNameRegex = /\\..*/;\nconst stripUidRegex = /::\\d+$/;\nconst eventRegistry = {}; // Events storage\nlet uidEvent = 1;\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n};\nconst nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;\n}\nfunction getElementEvents(element) {\n const uid = makeEventUid(element);\n element.uidEvent = uid;\n eventRegistry[uid] = eventRegistry[uid] || {};\n return eventRegistry[uid];\n}\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, {\n delegateTarget: element\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn);\n }\n return fn.apply(element, [event]);\n };\n}\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector);\n for (let {\n target\n } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue;\n }\n hydrateObj(event, {\n delegateTarget: target\n });\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn);\n }\n return fn.apply(target, [event]);\n }\n }\n };\n}\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector);\n}\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string';\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : handler || delegationFunction;\n let typeEvent = getTypeEvent(originalTypeEvent);\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent;\n }\n return [isDelegated, callable, typeEvent];\n}\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {\n return fn.call(this, event);\n }\n };\n };\n callable = wrapFunction(callable);\n }\n const events = getElementEvents(element);\n const handlers = events[typeEvent] || (events[typeEvent] = {});\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null);\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff;\n return;\n }\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''));\n const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable);\n fn.delegationSelector = isDelegated ? handler : null;\n fn.callable = callable;\n fn.oneOff = oneOff;\n fn.uidEvent = uid;\n handlers[uid] = fn;\n element.addEventListener(typeEvent, fn, isDelegated);\n}\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector);\n if (!fn) {\n return;\n }\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));\n delete events[typeEvent][fn.uidEvent];\n}\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {};\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n}\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '');\n return customEvents[event] || event;\n}\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false);\n },\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true);\n },\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return;\n }\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction);\n const inNamespace = typeEvent !== originalTypeEvent;\n const events = getElementEvents(element);\n const storeElementEvent = events[typeEvent] || {};\n const isNamespace = originalTypeEvent.startsWith('.');\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return;\n }\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null);\n return;\n }\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));\n }\n }\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '');\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector);\n }\n }\n },\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null;\n }\n const $ = getjQuery();\n const typeEvent = getTypeEvent(event);\n const inNamespace = event !== typeEvent;\n let jQueryEvent = null;\n let bubbles = true;\n let nativeDispatch = true;\n let defaultPrevented = false;\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args);\n $(element).trigger(jQueryEvent);\n bubbles = !jQueryEvent.isPropagationStopped();\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();\n defaultPrevented = jQueryEvent.isDefaultPrevented();\n }\n const evt = hydrateObj(new Event(event, {\n bubbles,\n cancelable: true\n }), args);\n if (defaultPrevented) {\n evt.preventDefault();\n }\n if (nativeDispatch) {\n element.dispatchEvent(evt);\n }\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault();\n }\n return evt;\n }\n};\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value;\n } catch (_unused) {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value;\n }\n });\n }\n }\n return obj;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true;\n }\n if (value === 'false') {\n return false;\n }\n if (value === Number(value).toString()) {\n return Number(value);\n }\n if (value === '' || value === 'null') {\n return null;\n }\n if (typeof value !== 'string') {\n return value;\n }\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (_unused) {\n return value;\n }\n}\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);\n}\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);\n },\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);\n },\n getDataAttributes(element) {\n if (!element) {\n return {};\n }\n const attributes = {};\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '');\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length);\n attributes[pureKey] = normalizeData(element.dataset[key]);\n }\n return attributes;\n },\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {};\n }\n static get DefaultType() {\n return {};\n }\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!');\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n return config;\n }\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n };\n }\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property];\n const valueType = isElement(value) ? 'element' : toType(value);\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`);\n }\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.3';\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super();\n element = getElement(element);\n if (!element) {\n return;\n }\n this._element = element;\n this._config = this._getConfig(config);\n Data.set(this._element, this.constructor.DATA_KEY, this);\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY);\n EventHandler.off(this._element, this.constructor.EVENT_KEY);\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null;\n }\n }\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated);\n }\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY);\n }\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);\n }\n static get VERSION() {\n return VERSION;\n }\n static get DATA_KEY() {\n return `bs.${this.NAME}`;\n }\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`;\n }\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target');\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href');\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {\n return null;\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`;\n }\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;\n }\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null;\n};\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector));\n },\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector);\n },\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector));\n },\n parents(element, selector) {\n const parents = [];\n let ancestor = element.parentNode.closest(selector);\n while (ancestor) {\n parents.push(ancestor);\n ancestor = ancestor.parentNode.closest(selector);\n }\n return parents;\n },\n prev(element, selector) {\n let previous = element.previousElementSibling;\n while (previous) {\n if (previous.matches(selector)) {\n return [previous];\n }\n previous = previous.previousElementSibling;\n }\n return [];\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling;\n while (next) {\n if (next.matches(selector)) {\n return [next];\n }\n next = next.nextElementSibling;\n }\n return [];\n },\n focusableChildren(element) {\n const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable=\"true\"]'].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',');\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el));\n },\n getSelectorFromElement(element) {\n const selector = getSelector(element);\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null;\n }\n return null;\n },\n getElementFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.findOne(selector) : null;\n },\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element);\n return selector ? SelectorEngine.find(selector) : [];\n }\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`;\n const name = component.NAME;\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);\n const instance = component.getOrCreateInstance(target);\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]();\n });\n};\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$f = 'alert';\nconst DATA_KEY$a = 'bs.alert';\nconst EVENT_KEY$b = `.${DATA_KEY$a}`;\nconst EVENT_CLOSE = `close${EVENT_KEY$b}`;\nconst EVENT_CLOSED = `closed${EVENT_KEY$b}`;\nconst CLASS_NAME_FADE$5 = 'fade';\nconst CLASS_NAME_SHOW$8 = 'show';\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$f;\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);\n if (closeEvent.defaultPrevented) {\n return;\n }\n this._element.classList.remove(CLASS_NAME_SHOW$8);\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5);\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated);\n }\n\n // Private\n _destroyElement() {\n this._element.remove();\n EventHandler.trigger(this._element, EVENT_CLOSED);\n this.dispose();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close');\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$e = 'button';\nconst DATA_KEY$9 = 'bs.button';\nconst EVENT_KEY$a = `.${DATA_KEY$9}`;\nconst DATA_API_KEY$6 = '.data-api';\nconst CLASS_NAME_ACTIVE$3 = 'active';\nconst SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle=\"button\"]';\nconst EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`;\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME$e;\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3));\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this);\n if (config === 'toggle') {\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => {\n event.preventDefault();\n const button = event.target.closest(SELECTOR_DATA_TOGGLE$5);\n const data = Button.getOrCreateInstance(button);\n data.toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$d = 'swipe';\nconst EVENT_KEY$9 = '.bs.swipe';\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`;\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`;\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`;\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`;\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`;\nconst POINTER_TYPE_TOUCH = 'touch';\nconst POINTER_TYPE_PEN = 'pen';\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event';\nconst SWIPE_THRESHOLD = 40;\nconst Default$c = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n};\nconst DefaultType$c = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n};\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super();\n this._element = element;\n if (!element || !Swipe.isSupported()) {\n return;\n }\n this._config = this._getConfig(config);\n this._deltaX = 0;\n this._supportPointerEvents = Boolean(window.PointerEvent);\n this._initEvents();\n }\n\n // Getters\n static get Default() {\n return Default$c;\n }\n static get DefaultType() {\n return DefaultType$c;\n }\n static get NAME() {\n return NAME$d;\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY$9);\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX;\n return;\n }\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX;\n }\n }\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX;\n }\n this._handleSwipe();\n execute(this._config.endCallback);\n }\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;\n }\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX);\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return;\n }\n const direction = absDeltaX / this._deltaX;\n this._deltaX = 0;\n if (!direction) {\n return;\n }\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);\n }\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));\n }\n }\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$c = 'carousel';\nconst DATA_KEY$8 = 'bs.carousel';\nconst EVENT_KEY$8 = `.${DATA_KEY$8}`;\nconst DATA_API_KEY$5 = '.data-api';\nconst ARROW_LEFT_KEY$1 = 'ArrowLeft';\nconst ARROW_RIGHT_KEY$1 = 'ArrowRight';\nconst TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next';\nconst ORDER_PREV = 'prev';\nconst DIRECTION_LEFT = 'left';\nconst DIRECTION_RIGHT = 'right';\nconst EVENT_SLIDE = `slide${EVENT_KEY$8}`;\nconst EVENT_SLID = `slid${EVENT_KEY$8}`;\nconst EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`;\nconst EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`;\nconst EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`;\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`;\nconst EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`;\nconst CLASS_NAME_CAROUSEL = 'carousel';\nconst CLASS_NAME_ACTIVE$2 = 'active';\nconst CLASS_NAME_SLIDE = 'slide';\nconst CLASS_NAME_END = 'carousel-item-end';\nconst CLASS_NAME_START = 'carousel-item-start';\nconst CLASS_NAME_NEXT = 'carousel-item-next';\nconst CLASS_NAME_PREV = 'carousel-item-prev';\nconst SELECTOR_ACTIVE = '.active';\nconst SELECTOR_ITEM = '.carousel-item';\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM;\nconst SELECTOR_ITEM_IMG = '.carousel-item img';\nconst SELECTOR_INDICATORS = '.carousel-indicators';\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]';\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]';\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT\n};\nconst Default$b = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n};\nconst DefaultType$b = {\n interval: '(number|boolean)',\n // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._interval = null;\n this._activeElement = null;\n this._isSliding = false;\n this.touchTimeout = null;\n this._swipeHelper = null;\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element);\n this._addEventListeners();\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$b;\n }\n static get DefaultType() {\n return DefaultType$b;\n }\n static get NAME() {\n return NAME$c;\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT);\n }\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next();\n }\n }\n prev() {\n this._slide(ORDER_PREV);\n }\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element);\n }\n this._clearInterval();\n }\n cycle() {\n this._clearInterval();\n this._updateInterval();\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval);\n }\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle());\n return;\n }\n this.cycle();\n }\n to(index) {\n const items = this._getItems();\n if (index > items.length - 1 || index < 0) {\n return;\n }\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index));\n return;\n }\n const activeIndex = this._getItemIndex(this._getActive());\n if (activeIndex === index) {\n return;\n }\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV;\n this._slide(order, items[index]);\n }\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose();\n }\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval;\n return config;\n }\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event));\n }\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause());\n EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle());\n }\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners();\n }\n }\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault());\n }\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return;\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause();\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout);\n }\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval);\n };\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n };\n this._swipeHelper = new Swipe(this._element, swipeConfig);\n }\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n const direction = KEY_TO_DIRECTION[event.key];\n if (direction) {\n event.preventDefault();\n this._slide(this._directionToOrder(direction));\n }\n }\n _getItemIndex(element) {\n return this._getItems().indexOf(element);\n }\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return;\n }\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement);\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2);\n activeIndicator.removeAttribute('aria-current');\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement);\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2);\n newActiveIndicator.setAttribute('aria-current', 'true');\n }\n }\n _updateInterval() {\n const element = this._activeElement || this._getActive();\n if (!element) {\n return;\n }\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10);\n this._config.interval = elementInterval || this._config.defaultInterval;\n }\n _slide(order, element = null) {\n if (this._isSliding) {\n return;\n }\n const activeElement = this._getActive();\n const isNext = order === ORDER_NEXT;\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap);\n if (nextElement === activeElement) {\n return;\n }\n const nextElementIndex = this._getItemIndex(nextElement);\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n });\n };\n const slideEvent = triggerEvent(EVENT_SLIDE);\n if (slideEvent.defaultPrevented) {\n return;\n }\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return;\n }\n const isCycling = Boolean(this._interval);\n this.pause();\n this._isSliding = true;\n this._setActiveIndicatorElement(nextElementIndex);\n this._activeElement = nextElement;\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END;\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV;\n nextElement.classList.add(orderClassName);\n reflow(nextElement);\n activeElement.classList.add(directionalClassName);\n nextElement.classList.add(directionalClassName);\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName);\n nextElement.classList.add(CLASS_NAME_ACTIVE$2);\n activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName);\n this._isSliding = false;\n triggerEvent(EVENT_SLID);\n };\n this._queueCallback(completeCallBack, activeElement, this._isAnimated());\n if (isCycling) {\n this.cycle();\n }\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE);\n }\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element);\n }\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element);\n }\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n }\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT;\n }\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV;\n }\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT;\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config);\n if (typeof config === 'number') {\n data.to(config);\n return;\n }\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return;\n }\n event.preventDefault();\n const carousel = Carousel.getOrCreateInstance(target);\n const slideIndex = this.getAttribute('data-bs-slide-to');\n if (slideIndex) {\n carousel.to(slideIndex);\n carousel._maybeEnableCycle();\n return;\n }\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next();\n carousel._maybeEnableCycle();\n return;\n }\n carousel.prev();\n carousel._maybeEnableCycle();\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$3, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE);\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel);\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$b = 'collapse';\nconst DATA_KEY$7 = 'bs.collapse';\nconst EVENT_KEY$7 = `.${DATA_KEY$7}`;\nconst DATA_API_KEY$4 = '.data-api';\nconst EVENT_SHOW$6 = `show${EVENT_KEY$7}`;\nconst EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`;\nconst EVENT_HIDE$6 = `hide${EVENT_KEY$7}`;\nconst EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`;\nconst EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`;\nconst CLASS_NAME_SHOW$7 = 'show';\nconst CLASS_NAME_COLLAPSE = 'collapse';\nconst CLASS_NAME_COLLAPSING = 'collapsing';\nconst CLASS_NAME_COLLAPSED = 'collapsed';\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`;\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal';\nconst WIDTH = 'width';\nconst HEIGHT = 'height';\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing';\nconst SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle=\"collapse\"]';\nconst Default$a = {\n parent: null,\n toggle: true\n};\nconst DefaultType$a = {\n parent: '(null|element)',\n toggle: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isTransitioning = false;\n this._triggerArray = [];\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4);\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem);\n const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element);\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem);\n }\n }\n this._initializeChildren();\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown());\n }\n if (this._config.toggle) {\n this.toggle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$a;\n }\n static get DefaultType() {\n return DefaultType$a;\n }\n static get NAME() {\n return NAME$b;\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide();\n } else {\n this.show();\n }\n }\n show() {\n if (this._isTransitioning || this._isShown()) {\n return;\n }\n let activeChildren = [];\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, {\n toggle: false\n }));\n }\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n for (const activeInstance of activeChildren) {\n activeInstance.hide();\n }\n const dimension = this._getDimension();\n this._element.classList.remove(CLASS_NAME_COLLAPSE);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.style[dimension] = 0;\n this._addAriaAndCollapsedClass(this._triggerArray, true);\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n this._element.style[dimension] = '';\n EventHandler.trigger(this._element, EVENT_SHOWN$6);\n };\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n const scrollSize = `scroll${capitalizedDimension}`;\n this._queueCallback(complete, this._element, true);\n this._element.style[dimension] = `${this._element[scrollSize]}px`;\n }\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return;\n }\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6);\n if (startEvent.defaultPrevented) {\n return;\n }\n const dimension = this._getDimension();\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`;\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_COLLAPSING);\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7);\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger);\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false);\n }\n }\n this._isTransitioning = true;\n const complete = () => {\n this._isTransitioning = false;\n this._element.classList.remove(CLASS_NAME_COLLAPSING);\n this._element.classList.add(CLASS_NAME_COLLAPSE);\n EventHandler.trigger(this._element, EVENT_HIDDEN$6);\n };\n this._element.style[dimension] = '';\n this._queueCallback(complete, this._element, true);\n }\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW$7);\n }\n\n // Private\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle); // Coerce string values\n config.parent = getElement(config.parent);\n return config;\n }\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT;\n }\n _initializeChildren() {\n if (!this._config.parent) {\n return;\n }\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4);\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element);\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected));\n }\n }\n }\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent);\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element));\n }\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return;\n }\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen);\n element.setAttribute('aria-expanded', isOpen);\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {};\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config);\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n }\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') {\n event.preventDefault();\n }\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, {\n toggle: false\n }).toggle();\n }\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$a = 'dropdown';\nconst DATA_KEY$6 = 'bs.dropdown';\nconst EVENT_KEY$6 = `.${DATA_KEY$6}`;\nconst DATA_API_KEY$3 = '.data-api';\nconst ESCAPE_KEY$2 = 'Escape';\nconst TAB_KEY$1 = 'Tab';\nconst ARROW_UP_KEY$1 = 'ArrowUp';\nconst ARROW_DOWN_KEY$1 = 'ArrowDown';\nconst RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE$5 = `hide${EVENT_KEY$6}`;\nconst EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`;\nconst EVENT_SHOW$5 = `show${EVENT_KEY$6}`;\nconst EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`;\nconst EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`;\nconst CLASS_NAME_SHOW$6 = 'show';\nconst CLASS_NAME_DROPUP = 'dropup';\nconst CLASS_NAME_DROPEND = 'dropend';\nconst CLASS_NAME_DROPSTART = 'dropstart';\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center';\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center';\nconst SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)';\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`;\nconst SELECTOR_MENU = '.dropdown-menu';\nconst SELECTOR_NAVBAR = '.navbar';\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav';\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start';\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end';\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start';\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end';\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start';\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start';\nconst PLACEMENT_TOPCENTER = 'top';\nconst PLACEMENT_BOTTOMCENTER = 'bottom';\nconst Default$9 = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n};\nconst DefaultType$9 = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n};\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._popper = null;\n this._parent = this._element.parentNode; // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent);\n this._inNavbar = this._detectNavbar();\n }\n\n // Getters\n static get Default() {\n return Default$9;\n }\n static get DefaultType() {\n return DefaultType$9;\n }\n static get NAME() {\n return NAME$a;\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show();\n }\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget);\n if (showEvent.defaultPrevented) {\n return;\n }\n this._createPopper();\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n this._element.focus();\n this._element.setAttribute('aria-expanded', true);\n this._menu.classList.add(CLASS_NAME_SHOW$6);\n this._element.classList.add(CLASS_NAME_SHOW$6);\n EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget);\n }\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return;\n }\n const relatedTarget = {\n relatedTarget: this._element\n };\n this._completeHide(relatedTarget);\n }\n dispose() {\n if (this._popper) {\n this._popper.destroy();\n }\n super.dispose();\n }\n update() {\n this._inNavbar = this._detectNavbar();\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n if (this._popper) {\n this._popper.destroy();\n }\n this._menu.classList.remove(CLASS_NAME_SHOW$6);\n this._element.classList.remove(CLASS_NAME_SHOW$6);\n this._element.setAttribute('aria-expanded', 'false');\n Manipulator.removeDataAttribute(this._menu, 'popper');\n EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);\n }\n _getConfig(config) {\n config = super._getConfig(config);\n if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME$a.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`);\n }\n return config;\n }\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org)');\n }\n let referenceElement = this._element;\n if (this._config.reference === 'parent') {\n referenceElement = this._parent;\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference);\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference;\n }\n const popperConfig = this._getPopperConfig();\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig);\n }\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW$6);\n }\n _getPlacement() {\n const parentDropdown = this._parent;\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER;\n }\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER;\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end';\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n }\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM;\n }\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null;\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n };\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }];\n }\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _selectMenuItem({\n key,\n target\n }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element));\n if (!items.length) {\n return;\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus();\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) {\n return;\n }\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle);\n if (!context || context._config.autoClose === false) {\n continue;\n }\n const composedPath = event.composedPath();\n const isMenuTarget = composedPath.includes(context._menu);\n if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) {\n continue;\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue;\n }\n const relatedTarget = {\n relatedTarget: context._element\n };\n if (event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n context._completeHide(relatedTarget);\n }\n }\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName);\n const isEscapeEvent = event.key === ESCAPE_KEY$2;\n const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key);\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return;\n }\n if (isInput && !isEscapeEvent) {\n return;\n }\n event.preventDefault();\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode);\n const instance = Dropdown.getOrCreateInstance(getToggleButton);\n if (isUpOrDownEvent) {\n event.stopPropagation();\n instance.show();\n instance._selectMenuItem(event);\n return;\n }\n if (instance._isShown()) {\n // else is escape and we check if it is shown\n event.stopPropagation();\n instance.hide();\n getToggleButton.focus();\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus);\nEventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) {\n event.preventDefault();\n Dropdown.getOrCreateInstance(this).toggle();\n});\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$9 = 'backdrop';\nconst CLASS_NAME_FADE$4 = 'fade';\nconst CLASS_NAME_SHOW$5 = 'show';\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`;\nconst Default$8 = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true,\n // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n};\nconst DefaultType$8 = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n};\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isAppended = false;\n this._element = null;\n }\n\n // Getters\n static get Default() {\n return Default$8;\n }\n static get DefaultType() {\n return DefaultType$8;\n }\n static get NAME() {\n return NAME$9;\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._append();\n const element = this._getElement();\n if (this._config.isAnimated) {\n reflow(element);\n }\n element.classList.add(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n execute(callback);\n });\n }\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback);\n return;\n }\n this._getElement().classList.remove(CLASS_NAME_SHOW$5);\n this._emulateAnimation(() => {\n this.dispose();\n execute(callback);\n });\n }\n dispose() {\n if (!this._isAppended) {\n return;\n }\n EventHandler.off(this._element, EVENT_MOUSEDOWN);\n this._element.remove();\n this._isAppended = false;\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div');\n backdrop.className = this._config.className;\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE$4);\n }\n this._element = backdrop;\n }\n return this._element;\n }\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement);\n return config;\n }\n _append() {\n if (this._isAppended) {\n return;\n }\n const element = this._getElement();\n this._config.rootElement.append(element);\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback);\n });\n this._isAppended = true;\n }\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated);\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$8 = 'focustrap';\nconst DATA_KEY$5 = 'bs.focustrap';\nconst EVENT_KEY$5 = `.${DATA_KEY$5}`;\nconst EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`;\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`;\nconst TAB_KEY = 'Tab';\nconst TAB_NAV_FORWARD = 'forward';\nconst TAB_NAV_BACKWARD = 'backward';\nconst Default$7 = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n};\nconst DefaultType$7 = {\n autofocus: 'boolean',\n trapElement: 'element'\n};\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n this._isActive = false;\n this._lastTabNavDirection = null;\n }\n\n // Getters\n static get Default() {\n return Default$7;\n }\n static get DefaultType() {\n return DefaultType$7;\n }\n static get NAME() {\n return NAME$8;\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return;\n }\n if (this._config.autofocus) {\n this._config.trapElement.focus();\n }\n EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event));\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));\n this._isActive = true;\n }\n deactivate() {\n if (!this._isActive) {\n return;\n }\n this._isActive = false;\n EventHandler.off(document, EVENT_KEY$5);\n }\n\n // Private\n _handleFocusin(event) {\n const {\n trapElement\n } = this._config;\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return;\n }\n const elements = SelectorEngine.focusableChildren(trapElement);\n if (elements.length === 0) {\n trapElement.focus();\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus();\n } else {\n elements[0].focus();\n }\n }\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return;\n }\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\nconst SELECTOR_STICKY_CONTENT = '.sticky-top';\nconst PROPERTY_PADDING = 'padding-right';\nconst PROPERTY_MARGIN = 'margin-right';\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body;\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth;\n return Math.abs(window.innerWidth - documentWidth);\n }\n hide() {\n const width = this.getWidth();\n this._disableOverFlow();\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);\n }\n reset() {\n this._resetElementAttributes(this._element, 'overflow');\n this._resetElementAttributes(this._element, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);\n }\n isOverflowing() {\n return this.getWidth() > 0;\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow');\n this._element.style.overflow = 'hidden';\n }\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth();\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return;\n }\n this._saveInitialAttribute(element, styleProperty);\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty);\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue);\n }\n }\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty);\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty);\n return;\n }\n Manipulator.removeDataAttribute(element, styleProperty);\n element.style.setProperty(styleProperty, value);\n };\n this._applyManipulationCallback(selector, manipulationCallBack);\n }\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector);\n return;\n }\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel);\n }\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$7 = 'modal';\nconst DATA_KEY$4 = 'bs.modal';\nconst EVENT_KEY$4 = `.${DATA_KEY$4}`;\nconst DATA_API_KEY$2 = '.data-api';\nconst ESCAPE_KEY$1 = 'Escape';\nconst EVENT_HIDE$4 = `hide${EVENT_KEY$4}`;\nconst EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`;\nconst EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`;\nconst EVENT_SHOW$4 = `show${EVENT_KEY$4}`;\nconst EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`;\nconst EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`;\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`;\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`;\nconst EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`;\nconst EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`;\nconst CLASS_NAME_OPEN = 'modal-open';\nconst CLASS_NAME_FADE$3 = 'fade';\nconst CLASS_NAME_SHOW$4 = 'show';\nconst CLASS_NAME_STATIC = 'modal-static';\nconst OPEN_SELECTOR$1 = '.modal.show';\nconst SELECTOR_DIALOG = '.modal-dialog';\nconst SELECTOR_MODAL_BODY = '.modal-body';\nconst SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle=\"modal\"]';\nconst Default$6 = {\n backdrop: true,\n focus: true,\n keyboard: true\n};\nconst DefaultType$6 = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element);\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._isShown = false;\n this._isTransitioning = false;\n this._scrollBar = new ScrollBarHelper();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$6;\n }\n static get DefaultType() {\n return DefaultType$6;\n }\n static get NAME() {\n return NAME$7;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._isTransitioning = true;\n this._scrollBar.hide();\n document.body.classList.add(CLASS_NAME_OPEN);\n this._adjustDialog();\n this._backdrop.show(() => this._showElement(relatedTarget));\n }\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._isShown = false;\n this._isTransitioning = true;\n this._focustrap.deactivate();\n this._element.classList.remove(CLASS_NAME_SHOW$4);\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated());\n }\n dispose() {\n EventHandler.off(window, EVENT_KEY$4);\n EventHandler.off(this._dialog, EVENT_KEY$4);\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n handleUpdate() {\n this._adjustDialog();\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop),\n // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element);\n }\n this._element.style.display = 'block';\n this._element.removeAttribute('aria-hidden');\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.scrollTop = 0;\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog);\n if (modalBody) {\n modalBody.scrollTop = 0;\n }\n reflow(this._element);\n this._element.classList.add(CLASS_NAME_SHOW$4);\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate();\n }\n this._isTransitioning = false;\n EventHandler.trigger(this._element, EVENT_SHOWN$4, {\n relatedTarget\n });\n };\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated());\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => {\n if (event.key !== ESCAPE_KEY$1) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n this._triggerBackdropTransition();\n });\n EventHandler.on(window, EVENT_RESIZE$1, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog();\n }\n });\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return;\n }\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition();\n return;\n }\n if (this._config.backdrop) {\n this.hide();\n }\n });\n });\n }\n _hideModal() {\n this._element.style.display = 'none';\n this._element.setAttribute('aria-hidden', true);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n this._isTransitioning = false;\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN);\n this._resetAdjustments();\n this._scrollBar.reset();\n EventHandler.trigger(this._element, EVENT_HIDDEN$4);\n });\n }\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE$3);\n }\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1);\n if (hideEvent.defaultPrevented) {\n return;\n }\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const initialOverflowY = this._element.style.overflowY;\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return;\n }\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n this._element.classList.add(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC);\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY;\n }, this._dialog);\n }, this._dialog);\n this._element.focus();\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n const scrollbarWidth = this._scrollBar.getWidth();\n const isBodyOverflowing = scrollbarWidth > 0;\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft';\n this._element.style[property] = `${scrollbarWidth}px`;\n }\n }\n _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](relatedTarget);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n EventHandler.one(target, EVENT_SHOW$4, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$4, () => {\n if (isVisible(this)) {\n this.focus();\n }\n });\n });\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1);\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide();\n }\n const data = Modal.getOrCreateInstance(target);\n data.toggle(this);\n});\nenableDismissTrigger(Modal);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$6 = 'offcanvas';\nconst DATA_KEY$3 = 'bs.offcanvas';\nconst EVENT_KEY$3 = `.${DATA_KEY$3}`;\nconst DATA_API_KEY$1 = '.data-api';\nconst EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst ESCAPE_KEY = 'Escape';\nconst CLASS_NAME_SHOW$3 = 'show';\nconst CLASS_NAME_SHOWING$1 = 'showing';\nconst CLASS_NAME_HIDING = 'hiding';\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop';\nconst OPEN_SELECTOR = '.offcanvas.show';\nconst EVENT_SHOW$3 = `show${EVENT_KEY$3}`;\nconst EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`;\nconst EVENT_HIDE$3 = `hide${EVENT_KEY$3}`;\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`;\nconst EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`;\nconst EVENT_RESIZE = `resize${EVENT_KEY$3}`;\nconst EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`;\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`;\nconst SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle=\"offcanvas\"]';\nconst Default$5 = {\n backdrop: true,\n keyboard: true,\n scroll: false\n};\nconst DefaultType$5 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n};\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n this._isShown = false;\n this._backdrop = this._initializeBackDrop();\n this._focustrap = this._initializeFocusTrap();\n this._addEventListeners();\n }\n\n // Getters\n static get Default() {\n return Default$5;\n }\n static get DefaultType() {\n return DefaultType$5;\n }\n static get NAME() {\n return NAME$6;\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n }\n show(relatedTarget) {\n if (this._isShown) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, {\n relatedTarget\n });\n if (showEvent.defaultPrevented) {\n return;\n }\n this._isShown = true;\n this._backdrop.show();\n if (!this._config.scroll) {\n new ScrollBarHelper().hide();\n }\n this._element.setAttribute('aria-modal', true);\n this._element.setAttribute('role', 'dialog');\n this._element.classList.add(CLASS_NAME_SHOWING$1);\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate();\n }\n this._element.classList.add(CLASS_NAME_SHOW$3);\n this._element.classList.remove(CLASS_NAME_SHOWING$1);\n EventHandler.trigger(this._element, EVENT_SHOWN$3, {\n relatedTarget\n });\n };\n this._queueCallback(completeCallBack, this._element, true);\n }\n hide() {\n if (!this._isShown) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3);\n if (hideEvent.defaultPrevented) {\n return;\n }\n this._focustrap.deactivate();\n this._element.blur();\n this._isShown = false;\n this._element.classList.add(CLASS_NAME_HIDING);\n this._backdrop.hide();\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING);\n this._element.removeAttribute('aria-modal');\n this._element.removeAttribute('role');\n if (!this._config.scroll) {\n new ScrollBarHelper().reset();\n }\n EventHandler.trigger(this._element, EVENT_HIDDEN$3);\n };\n this._queueCallback(completeCallback, this._element, true);\n }\n dispose() {\n this._backdrop.dispose();\n this._focustrap.deactivate();\n super.dispose();\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n return;\n }\n this.hide();\n };\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop);\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n });\n }\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n });\n }\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return;\n }\n if (this._config.keyboard) {\n this.hide();\n return;\n }\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED);\n });\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config](this);\n });\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) {\n const target = SelectorEngine.getElementFromSelector(this);\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault();\n }\n if (isDisabled(this)) {\n return;\n }\n EventHandler.one(target, EVENT_HIDDEN$3, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus();\n }\n });\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR);\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide();\n }\n const data = Offcanvas.getOrCreateInstance(target);\n data.toggle(this);\n});\nEventHandler.on(window, EVENT_LOAD_DATA_API$2, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show();\n }\n});\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide();\n }\n }\n});\nenableDismissTrigger(Offcanvas);\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\nconst DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n};\n// js-docs-end allow-list\n\nconst uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\n// eslint-disable-next-line unicorn/better-regex\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase();\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));\n }\n return true;\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));\n};\nfunction sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml;\n }\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml);\n }\n const domParser = new window.DOMParser();\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'));\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase();\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove();\n continue;\n }\n const attributeList = [].concat(...element.attributes);\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName);\n }\n }\n }\n return createdDocument.body.innerHTML;\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$5 = 'TemplateFactory';\nconst Default$4 = {\n allowList: DefaultAllowlist,\n content: {},\n // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '
'\n};\nconst DefaultType$4 = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n};\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n};\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super();\n this._config = this._getConfig(config);\n }\n\n // Getters\n static get Default() {\n return Default$4;\n }\n static get DefaultType() {\n return DefaultType$4;\n }\n static get NAME() {\n return NAME$5;\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);\n }\n hasContent() {\n return this.getContent().length > 0;\n }\n changeContent(content) {\n this._checkContent(content);\n this._config.content = {\n ...this._config.content,\n ...content\n };\n return this;\n }\n toHtml() {\n const templateWrapper = document.createElement('div');\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template);\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector);\n }\n const template = templateWrapper.children[0];\n const extraClass = this._resolvePossibleFunction(this._config.extraClass);\n if (extraClass) {\n template.classList.add(...extraClass.split(' '));\n }\n return template;\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config);\n this._checkContent(config.content);\n }\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({\n selector,\n entry: content\n }, DefaultContentType);\n }\n }\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template);\n if (!templateElement) {\n return;\n }\n content = this._resolvePossibleFunction(content);\n if (!content) {\n templateElement.remove();\n return;\n }\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement);\n return;\n }\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content);\n return;\n }\n templateElement.textContent = content;\n }\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this]);\n }\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = '';\n templateElement.append(element);\n return;\n }\n templateElement.textContent = element.textContent;\n }\n}\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$4 = 'tooltip';\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']);\nconst CLASS_NAME_FADE$2 = 'fade';\nconst CLASS_NAME_MODAL = 'modal';\nconst CLASS_NAME_SHOW$2 = 'show';\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`;\nconst EVENT_MODAL_HIDE = 'hide.bs.modal';\nconst TRIGGER_HOVER = 'hover';\nconst TRIGGER_FOCUS = 'focus';\nconst TRIGGER_CLICK = 'click';\nconst TRIGGER_MANUAL = 'manual';\nconst EVENT_HIDE$2 = 'hide';\nconst EVENT_HIDDEN$2 = 'hidden';\nconst EVENT_SHOW$2 = 'show';\nconst EVENT_SHOWN$2 = 'shown';\nconst EVENT_INSERTED = 'inserted';\nconst EVENT_CLICK$1 = 'click';\nconst EVENT_FOCUSIN$1 = 'focusin';\nconst EVENT_FOCUSOUT$1 = 'focusout';\nconst EVENT_MOUSEENTER = 'mouseenter';\nconst EVENT_MOUSELEAVE = 'mouseleave';\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n};\nconst Default$3 = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '
' + '
' + '
' + '
',\n title: '',\n trigger: 'hover focus'\n};\nconst DefaultType$3 = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n};\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org)');\n }\n super(element, config);\n\n // Private\n this._isEnabled = true;\n this._timeout = 0;\n this._isHovered = null;\n this._activeTrigger = {};\n this._popper = null;\n this._templateFactory = null;\n this._newContent = null;\n\n // Protected\n this.tip = null;\n this._setListeners();\n if (!this._config.selector) {\n this._fixTitle();\n }\n }\n\n // Getters\n static get Default() {\n return Default$3;\n }\n static get DefaultType() {\n return DefaultType$3;\n }\n static get NAME() {\n return NAME$4;\n }\n\n // Public\n enable() {\n this._isEnabled = true;\n }\n disable() {\n this._isEnabled = false;\n }\n toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n }\n toggle() {\n if (!this._isEnabled) {\n return;\n }\n this._activeTrigger.click = !this._activeTrigger.click;\n if (this._isShown()) {\n this._leave();\n return;\n }\n this._enter();\n }\n dispose() {\n clearTimeout(this._timeout);\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'));\n }\n this._disposePopper();\n super.dispose();\n }\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements');\n }\n if (!(this._isWithContent() && this._isEnabled)) {\n return;\n }\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2));\n const shadowRoot = findShadowRoot(this._element);\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element);\n if (showEvent.defaultPrevented || !isInTheDom) {\n return;\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper();\n const tip = this._getTipElement();\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'));\n const {\n container\n } = this._config;\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip);\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED));\n }\n this._popper = this._createPopper(tip);\n tip.classList.add(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop);\n }\n }\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2));\n if (this._isHovered === false) {\n this._leave();\n }\n this._isHovered = false;\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n hide() {\n if (!this._isShown()) {\n return;\n }\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2));\n if (hideEvent.defaultPrevented) {\n return;\n }\n const tip = this._getTipElement();\n tip.classList.remove(CLASS_NAME_SHOW$2);\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop);\n }\n }\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n this._isHovered = null; // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return;\n }\n if (!this._isHovered) {\n this._disposePopper();\n }\n this._element.removeAttribute('aria-describedby');\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2));\n };\n this._queueCallback(complete, this.tip, this._isAnimated());\n }\n update() {\n if (this._popper) {\n this._popper.update();\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle());\n }\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate());\n }\n return this.tip;\n }\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml();\n\n // TODO: remove this check in v6\n if (!tip) {\n return null;\n }\n tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2);\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`);\n const tipId = getUID(this.constructor.NAME).toString();\n tip.setAttribute('id', tipId);\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE$2);\n }\n return tip;\n }\n setContent(content) {\n this._newContent = content;\n if (this._isShown()) {\n this._disposePopper();\n this.show();\n }\n }\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content);\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n });\n }\n return this._templateFactory;\n }\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n };\n }\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title');\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig());\n }\n _isAnimated() {\n return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2);\n }\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2);\n }\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element]);\n const attachment = AttachmentMap[placement.toUpperCase()];\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment));\n }\n _getOffset() {\n const {\n offset\n } = this._config;\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10));\n }\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element);\n }\n return offset;\n }\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element]);\n }\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [{\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n }, {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }, {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n }, {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n }, {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement);\n }\n }]\n };\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [defaultBsPopperConfig])\n };\n }\n _setListeners() {\n const triggers = this._config.trigger.split(' ');\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context.toggle();\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1);\n const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1);\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n context._enter();\n });\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event);\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget);\n context._leave();\n });\n }\n }\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide();\n }\n };\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler);\n }\n _fixTitle() {\n const title = this._element.getAttribute('title');\n if (!title) {\n return;\n }\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title);\n }\n this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title');\n }\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true;\n return;\n }\n this._isHovered = true;\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show();\n }\n }, this._config.delay.show);\n }\n _leave() {\n if (this._isWithActiveTrigger()) {\n return;\n }\n this._isHovered = false;\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide();\n }\n }, this._config.delay.hide);\n }\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout);\n this._timeout = setTimeout(handler, timeout);\n }\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true);\n }\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element);\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute];\n }\n }\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n };\n config = this._mergeConfigObj(config);\n config = this._configAfterMerge(config);\n this._typeCheckConfig(config);\n return config;\n }\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container);\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n return config;\n }\n _getDelegateConfig() {\n const config = {};\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value;\n }\n }\n config.selector = false;\n config.trigger = 'manual';\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config;\n }\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy();\n this._popper = null;\n }\n if (this.tip) {\n this.tip.remove();\n this.tip = null;\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$3 = 'popover';\nconst SELECTOR_TITLE = '.popover-header';\nconst SELECTOR_CONTENT = '.popover-body';\nconst Default$2 = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '
' + '
' + '

' + '
' + '
',\n trigger: 'click'\n};\nconst DefaultType$2 = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n};\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default$2;\n }\n static get DefaultType() {\n return DefaultType$2;\n }\n static get NAME() {\n return NAME$3;\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent();\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n };\n }\n _getContent() {\n return this._resolvePossibleFunction(this._config.content);\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config);\n if (typeof config !== 'string') {\n return;\n }\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`);\n }\n data[config]();\n });\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover);\n\n/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n\n/**\n * Constants\n */\n\nconst NAME$2 = 'scrollspy';\nconst DATA_KEY$2 = 'bs.scrollspy';\nconst EVENT_KEY$2 = `.${DATA_KEY$2}`;\nconst DATA_API_KEY = '.data-api';\nconst EVENT_ACTIVATE = `activate${EVENT_KEY$2}`;\nconst EVENT_CLICK = `click${EVENT_KEY$2}`;\nconst EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`;\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\nconst CLASS_NAME_ACTIVE$1 = 'active';\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]';\nconst SELECTOR_TARGET_LINKS = '[href]';\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\nconst SELECTOR_NAV_LINKS = '.nav-link';\nconst SELECTOR_NAV_ITEMS = '.nav-item';\nconst SELECTOR_LIST_ITEMS = '.list-group-item';\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`;\nconst SELECTOR_DROPDOWN = '.dropdown';\nconst SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle';\nconst Default$1 = {\n offset: null,\n // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n};\nconst DefaultType$1 = {\n offset: '(number|null)',\n // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n};\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config);\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map();\n this._observableSections = new Map();\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element;\n this._activeTarget = null;\n this._observer = null;\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n };\n this.refresh(); // initialize\n }\n\n // Getters\n static get Default() {\n return Default$1;\n }\n static get DefaultType() {\n return DefaultType$1;\n }\n static get NAME() {\n return NAME$2;\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables();\n this._maybeEnableSmoothScroll();\n if (this._observer) {\n this._observer.disconnect();\n } else {\n this._observer = this._getNewObserver();\n }\n for (const section of this._observableSections.values()) {\n this._observer.observe(section);\n }\n }\n dispose() {\n this._observer.disconnect();\n super.dispose();\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body;\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin;\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value));\n }\n return config;\n }\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return;\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK);\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash);\n if (observableSection) {\n event.preventDefault();\n const root = this._rootElement || window;\n const height = observableSection.offsetTop - this._element.offsetTop;\n if (root.scrollTo) {\n root.scrollTo({\n top: height,\n behavior: 'smooth'\n });\n return;\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height;\n }\n });\n }\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n };\n return new IntersectionObserver(entries => this._observerCallback(entries), options);\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`);\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop;\n this._process(targetElement(entry));\n };\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop;\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop;\n this._previousScrollData.parentScrollTop = parentScrollTop;\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null;\n this._clearActiveClass(targetElement(entry));\n continue;\n }\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop;\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry);\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return;\n }\n continue;\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry);\n }\n }\n }\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map();\n this._observableSections = new Map();\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target);\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue;\n }\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element);\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor);\n this._observableSections.set(anchor.hash, observableSection);\n }\n }\n }\n _process(target) {\n if (this._activeTarget === target) {\n return;\n }\n this._clearActiveClass(this._config.target);\n this._activeTarget = target;\n target.classList.add(CLASS_NAME_ACTIVE$1);\n this._activateParents(target);\n EventHandler.trigger(this._element, EVENT_ACTIVATE, {\n relatedTarget: target\n });\n }\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1);\n return;\n }\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both
    and