From 8136cc239dcaa1bed742b225d2f25f1ed53b9db0 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Wed, 30 Jul 2025 16:55:15 +0200 Subject: [PATCH 01/50] fix for issue 6482. After the boundary properties are changed. the boundary is not updated. So the project still shows the old value. --- src/ansys/aedt/core/generic/configurations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/aedt/core/generic/configurations.py b/src/ansys/aedt/core/generic/configurations.py index 346fc4253e3f..aac39330acd2 100644 --- a/src/ansys/aedt/core/generic/configurations.py +++ b/src/ansys/aedt/core/generic/configurations.py @@ -893,6 +893,7 @@ def _update_boundaries(self, name, props): if bound and bound.name == name: if not self.options.skip_import_if_exists: bound.props.update({k: props[k] for k in bound.props if k in props}) + bound.update() return True bound = BoundaryObject(self._app, name, props, props["BoundType"]) if bound.props.get("Independent", None): From 196a21b4a6c86bbb4a829612c5099fdc0749b35c Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Wed, 6 Aug 2025 08:51:54 +0200 Subject: [PATCH 02/50] Icepak model reviewer toolkit to review and modify project settings in single ui --- .../icepak/icepak_model_reviewer.rst | 111 +++++ .../icepak_model_reviewer_initial_panel.png | Bin 0 -> 19441 bytes .../icepak_model_reviewer_ui_with_table.png | Bin 0 -> 80838 bytes .../icepak/icepak_model_reviewer.py | 342 ++++++++++++++++ .../icepak/icepak_model_reviewer/__init__.py | 0 .../icepak/icepak_model_reviewer/backend.py | 36 ++ .../configuration_data_processing.py | 378 ++++++++++++++++++ 7 files changed, 867 insertions(+) create mode 100644 doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst create mode 100644 doc/source/_static/extensions/icepak_model_reviewer_initial_panel.png create mode 100644 doc/source/_static/extensions/icepak_model_reviewer_ui_with_table.png create mode 100644 src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py create mode 100644 src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py create mode 100644 src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py create mode 100644 src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py diff --git a/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst new file mode 100644 index 000000000000..5b6e192ccda7 --- /dev/null +++ b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst @@ -0,0 +1,111 @@ +Icepak Model Reviewer +===================== + +The Icepak Model Reviewer extension allows users to inspect and modify details of an Icepak project. It enables +reviewing critical data such as boundary conditions, materials, and model-specific properties. + +The extension provides a graphical user interface (GUI) where the user can load a project, review its components, +and make necessary updates. + +The following image shows the extension GUI: + +.. image:: ../../../_static/extensions/icepak_model_reviewer_initial_panel.png + :width: 800 + :alt: Icepak Model Reviewer UI + +After the project is loaded by clicking, the GUI show tables +.. image:: ../../../_static/extensions/icepak_model_reviewer_ui_with_table.png + :width: 800 + :alt: Icepak Model Reviewer UI After loading Project + +Features +-------- + +- Load and inspect an Icepak project. +- Display editable tables showing: + - Boundary conditions + - Material properties + - Model details +- Update project parameters. + +Using the Extension +------------------- + +1. Open the **Automation** tab in the Icepak interface. +2. Click on the **Icepak Model Reviewer** icon under the Extension Manager. +3. In the GUI, interact with the following elements: + - **Load Project**: Load the Icepak project into the GUI. + - **Update Project**: Push any modifications made in the tables back to the project. +4. After the project is loaded: + - The GUI displays three main tables: + - **Boundary Conditions**: Lists all the boundary condition settings applied in the model. + - **Materials**: Shows the materials used and their key properties. + - **Models**: Displays model-specific data and configurations. + +Each table allows inline editing of values. To commit changes, click the **Update Project** button. This will apply all modifications to the currently loaded project. + +Tables Overview +--------------- + +**Boundary Conditions Table** + +This table displays the thermal boundary conditions defined in the Icepak project. +The data is organized with both read-only and editable fields to help users review and make updates. ++--------------------------+----------------------------------------------------------------------------------+ +| **Property** | **Description** | ++==========================+==================================================================================+ +| **Name** | Name of the boundary. This field is **read-only** and cannot be modified. | ++--------------------------+----------------------------------------------------------------------------------+ +| **Boundary Type** | Indicates whether the boundary is a *Block* or a *Source*. This is | +| | also a **read-only** field. | ++--------------------------+----------------------------------------------------------------------------------+ +| **BC Name 1 / BC Name 2**| Names of the boundary conditions applied (*Total Power*, *Power Density*, | +| | *Heat Transfer Coefficient*, *Temperature*). These fields are **read-only** | ++--------------------------+----------------------------------------------------------------------------------+ +| **Value 1 / Value 2** | Corresponding values for the selected boundary conditions. These fields | +| | are **editable**. | ++--------------------------+----------------------------------------------------------------------------------+ + + +**Materials Table** + + +This table displays material properties for all objects used in the Icepak project. +Some fields are read-only and provided for reference, while others can be modified depending on the simulation setup. + ++----------------------------------+--------------------------------------------------------------+ +| **Property** | **Description** | ++==================================+==============================================================+ +| **Name** | Material name (**read-only**) | ++----------------------------------+--------------------------------------------------------------+ +| **Material Type** | Indicates if the material is *Solid* or *Fluid* | +| | (**read-only**) | ++----------------------------------+--------------------------------------------------------------+ +| **Thermal Conductivity** | Thermal conductivity in **W/m·K** | ++----------------------------------+--------------------------------------------------------------+ +| **Mass Density** | Density in **kg/m³** | ++----------------------------------+--------------------------------------------------------------+ +| **Specific Heat** | Specific heat capacity in **J/kg·K** | ++----------------------------------+--------------------------------------------------------------+ +| **Thermal Expansion Coefficient**| Coefficient of thermal expansion in **1/K** | ++----------------------------------+--------------------------------------------------------------+ +| **Thermal Diffusivity** | Thermal diffusivity in **m²/s** | ++----------------------------------+--------------------------------------------------------------+ +| **Viscosity** | Dynamic viscosity in **Kg/m-s** | ++----------------------------------+--------------------------------------------------------------+ + + +**Models Table** + +This table lists the object-level settings related to modeling in the Icepak project. +It shows the assigned bulk and surface materials. Information about whether an object is model/ non-model object. + + + +Notes +----- + +- Ensure the CSV file for power map creation is formatted correctly before importing. +- Changes made in the tables are not applied to the project until the **Update Project** button is clicked. +- This extension is intended for reviewing model data efficiently without the need to navigate complex menus. + diff --git a/doc/source/_static/extensions/icepak_model_reviewer_initial_panel.png b/doc/source/_static/extensions/icepak_model_reviewer_initial_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..1f44e1b785ac7cfbe6cf00c938a1ef5318b90966 GIT binary patch literal 19441 zcmb6AWmp~069$Ol?#{v8-7Q#fm%zc@?cf9r?(S~E-Q6v?I{^;v58IbSekW2@Sq2pefCK>nfhs5aRUHBXGT`5N5CYu4eXZy(oPP&MS9KW) zh}s$A(|-btmAH~P1VlqT@|y|lKN%4utK$j*f#vq!2DxoX<^=(v5GMCkT+_?&G8fiZ zU+QD5k7)IGdzbbCulrLPK(%<}a5rJU9{U4+jKY(@XCH(XXXmOb5kjcTQ0kmAroD(Nyurtd;a>(@~Ee+Xx;Vbgv{&4gxScQgr68K{BF}~_0a+2 z5GVE2&(}BB@ZY5&Lc|DNbNQZIuJ9o+NE!iewC{gc#X+~nApRUo1pI*i9t!+F#juEu zJBR1L?fgWdsHpA^>icy6?t)Qx6qn#9c3A=v(E`>_qTF4HPbGB!u#*X`S>=L@BS_5h zU#7qQdo9-%LHG0dLk5mbq-+51D7!NsLU$fqsLsCq%`l6paQ6mgoJTNW@PDSd3J^9w zNB>G_qi(>D{7U^wDSn^%EVOY_Zyto2*R2-Rw|x?MuFV=)mX0nY$shmEcK-CZ0mjRM z;hiK29|ijY_4OhR6Uii}kuXRwFeV*=0!yrTPTT?<_9Xg7kX))*y8mB4J1{ajACFjZ zO2=sV=x;r-_4YQcpl|LXJ$yUMGSvr)>ajk)cm)$_%{Y(V62q>1`4+2{>3kUg@pd>L z4$DXEb@vcp_I~zl)ajjz!2@S2$3Aw)J3Q3n%9PMvpusIyk>BxcCAV=w9qgqt_7)C> zw+gDzm{}f@A?rmqLLV2nY%DV~0j^bLHmI3A-@dYpI{6I^4#!1t`*Y2?VzehfnqchJ zg@?)_lWEf&$n*R(5Db1imzqnQQ6T;bYKF$K6#J!oGJ8opvuoL$52s{kALL_rqfZRCGRnqHW=~wfxXNziB-F z9EDi*!v1OjSB@^S|Fuj-+hFK91lN7L(&dK+K?@E@{$~%qqzc#y1^CvZ&&=T(L!x|W zJvUcM6Kur(3TyXS`eF*>ty^5K8@&X@(?#(M#IuhJ&n1{?Jjr&nDC~-y#WI=k=EGXX zE=p@ydPr~t)IYk9dG$3NOJfCQ-09r#?RX2xD=5rFhWm-O2jqjg=`J$91HAQYISsn% z_G9i+M?&}Z_pRQRL{O(PjaScfYO7-uZH!OPzHbSWE+!>Z5KpCNuW{VHWu=uXns}$> ze*azXs&xD$JPOvgQ53XZ7=EBWQ{3`FgSg9vGiTWMyTQV1^Ej9Buma z`ZMJMqnE`#Am}bDyOwE&jK^|HixY#ZfVVg1AT*mZxyOkg_)HZ(lhgOI$QE+bGcfbw zb@v&DzS!brD=DweLYHUp6x^3#t7=Dl2`AwBlEMT8D^yU+c$iZZ%q0j78omV!S5jr== z{*#&xASuB=3a5m9k-=b~_&hxs_ug|nvk4P`U7Z8`-mw3^Ocd@~Vxraa0%6ShMjPG7 z2H8gd*LzV+XJ=FvHadtUm;L?{ z>lS+^LUJ}%*@K0ak(s2leFk0u9-HLOYwhV=tB%KC2w9JkQ-#WG@!TnQ9NzUppZ7t+*dtpKMfMpCFfe! z40k78s56E)XbW;AyDVpRIO>ly>YJ6cwEFtS@HA8??G0La55tSXymgp>UiUrl4UM?VCVXA@ZKE+vPj| zJ&+SW$u!F+yjWX0T@0PAc3kT?a&Bm!=3pz^K`JF&6eF?n8q}=k>7Z=c9H#fJ#5P4tE2vuAxYe6wOr}pG#P4IZ=*&^%>R{2U?$amsv z-B*fnJ37N1SQ*Txf$euDy-Q|UkQvvI8SJQdBEQ8>GQ%Jv`be9`5}w0#z%}{0^KyG^ z_K!)(H;sdTLzU~PZa;5j@s-WX>G^d&@5!_1%$) zxRLRdLS*coP6b((f+JEhVF zRd7fwi+)WUamp`;$N3FT*M`r@sy#19n{c20#w7VH;?-S_q4Q(pF;k{iLH!|3$ECEJ z8Qf#Oa)F50dU(d?VA`qB6SjB}^S33EG&D<-$1Ub7^j7fr*Jwl=qk1#u*rUOTg@HfQ zwUflyl6TDw;t`Pzk%4I=#>RWod*;sn4LtOiyxS&rdy>489yY~S=p$%`D*QVai%DVo z^>O_Zovo>O7UWFhCS)zT(su~B=qKM`oN!l$li4i3GPd*XwrPV=F?fjNy+=2Z)9E^+ z+qR{%!axy0mYhNhJW-3G8#a)zUhH~&tMN>+gY2&b0(iJqRQm{C@B!l6LtVh=6d@Of z*J~|9xq224X9PwV{D*zoE&f%y@o%eE#+=J97p!l5s^174o4dih& zd&0)@J|F+Qxj(vYy3}TkkzYgpZt2mpk|7>^ldmMYcR8eqxIB-nA0B4x~HT4gb5=MZ~ zz8=)3+;G)~JU{ugq5p?zwQEDH(Rj2O(e>X1h-bb{idEkR>Rucp^WkWTV!v!}r3OWd z{%fw%WYG5uAAz?}e#Zc3&evYH_GefAoT@M|<4|5VYe5IS_>=>F@~aV1zH-Gmih zd$T&^KV>iqMsoktQ7!NPbWDbp|8E_Lw-q>=#JnDZi2p%b)KH1Ql@+c1HYVu*6Oi9n zkp1iJ{}-75zi|35DTn7qlJm|^-4wh-@nSVXKY^SNM3lH6`2pm^rVaCD0nNHB03sqa z-5m7H=IN73us*-?3@ZX^d{|i-9Wx6{Y%f)CG}hnc1yT7Ds4`{J;?qh}EiJ05VwW&d%WlS0#x)^9la2fJ`j!?hQbI!g zlxJMqNTYzic>AMc zi6uwSv07HbgJ2ZW%xdW6W!&&BI&J ztAzF#b5rjl7a||^SSr1=(k3pAcyZ2xC-LQMLd|eHysBE_y9V6>W6f<0g#=T0bqge_ zd#ts_eQs~GG*!4fYftkk0TytNJE3j4xUc~+c46B{uzb~~(7H<6K$1(>LLSAYMpb8g zGh0<>Il`j^FKZwzT?;n18`Z&uB&@O{XWYr1&0+DN@?2F3x0+-EY300J*xb6RPRdL} z=x=#kVc_3Neb&C_)#q4tX2a`*u0sxAcirI9{s*tWiQjK%`%E4-YPVRPceKl#3m7o? zMBWk7)SxbX4m^g*fVW>%86{PcyJjZSRSp0P(x&Dgphy%uHY3Z{6P< zg?G)(gn3gmNu^9ISUhx`+IQ{r^Hzn}TdKzr`931a7)4BY9xS_iO;W%Kgp4}a3!=Ta zPWV&O7fI*NV-F2C+@xLB<<)Ul8?j}*>H8~6DrQnC$ZwaiV{j676y_aWHyr-qhs8PU zIMauU{!hFVT{9=^*!dhcz`ruSa<~^9nz0cv*h|-=M4xYPsd>>H4@W-p3hpSVOWN_R ze~VV!mHSqA>pThIPL^Egt(()5L%EramP<4wOA?Sxiwj{Md32Fp>d~e8bGmLXgsyj4 zT&{DR*}yGUE5?o!bk8R>EYF<11d@;Hrs>WZ9pL!q{e5&}CGJ=bE$L5+5|oOuIFsuq zh5}oFe^Zm|oOsnw-jR*e&Uh^;=tM0!E{+Z;q!thByPu0<#hPL(a!oWf{t1_zq^VM6 zx6_;9bJAMvj^%=(41Gy*84b58UWIzE=2tdv4hGagZSU{_{x(8rxV#dU!Vg9D1>(bg zcq_txaISjHV2@x4-@|cuI*2bmZ`qUfqUW?zU1tVY-@*Yzh}6CF8SD;#(xhyU(dp4@ zn`qFYK4K@MOG47OuqcXCosbqL;oxFSE?T5O?vDCS>Xwbj)>6wQ?YpNFBX69Oq?Url zc0_=s0}78v-VGW_Y`f!Sa>omh-wdfXn_gmj9L79_w=gm0FkuK?ja2VA}X{`SM4K|Qp)JmrEJww;Uo=S zv}NdE=G#n_(F7X(nXB`&Il$%aj~Wmd(YS%v3~V1*97jsSvkK4`E7K|{*=1Mfa!t(C zpbueTsQNKAgO1j!Rq)w0us1zBBWCK&8p=YcjV|TGuz;MUS_2vgk!r$_LTtXG2|S(+ z=P8*a{a{7qcjqKi7b1I(i<2&Qph7}BE>K#DC~7qQS%zO&EdePciZ7o{Q!RL|W|S68 zm7<;Iam2W}q^cVk+Kohirk0o=`!=ZS#{YL{B#tpHO6<38;Mt%ivBJdFt3K66Enagv zjm8@D!681upf*pDgd?)(CM`}W?cPBm&cU}<@v{S@9(i=S1`*;52BT4axG+*c3sMb> z63G4TN1f4+`M!W9TOOo8jk}lo$a+HX}l*<>afpxmrW%4_Jw9pwcZV=c6c>w`;bps786yZSl`tQOQX zV0~+O;7=@*-infncx(3>=wZ+?C@-i1D~TZG!CP5LH?47dc9FwFU}ZRCbz8Qix}ID0a#vu`kp@)i z^VkbhVep?jZnbd&Ft?RK^$kBqw?pGLe2I4+@%)u8DZx!4hQ&W*sU?P|oxpJ;m;}d8 z@Orj{rPK9$&twe`vW#f>?t{`Q@F|WN{7MqBTJEpLIsM@Y7Mwh2gX*> zC!YI7Kh?@BF||A>)~mZ4F?|eTDHk`~y#Dzfq1&?=`S!I1V@mY_4qwu}qq?EX=s_Fy z!nlRR*hNvlSOY?>h?hm2Ez!h58(r00e~ed;&nT5-!GUJOpO--f&%TPf-Iz~?*r@0- z3MK_h3?mwcKOlO+4b?pT5Dz;}+Z2cTObt|R>Rs+v z%q^cwbH#YKaBRCd{HRnO=3!H>NI>D0rbMB&gu^`M+s&{t{|-*@K{X}!a+ldsbIJ4X z1M&!52W!R6$ow|C-Qxr42#2-)su1%%hjz<(sOp?Om9#IB0h0`Gf48mZpSt0=uA{!z zH{or}(BhE2L++5tjt)@55;LFb$D+g~Uk_JWD1by#o3evVAdE-<)#eBp-M%XhuZ=I> zti>qXZ+1hMO`gr$Q%H%IA(f=s?UG%>`YZ$u5YqnxO4c;m5gXLhmmkFF{yC8io_)cq zqU%vLdOHJmZLwkRV*w+6*JLv4-@7oHdxQ}YjfA6=a@)XRbfSeIz1s&Lw!PC-L)p(8 zo(pOYrUWGMio!PX^Jt%&KSxNiRM#U_I3DMoZZob8)-02fwzdrvyCY)IC;(fv8aFzV zhaX+_kz>5$(G6^?XuVwi@zZ*r;j_FuVI9sDyF@z?IbgMKVBmvHa}SnRZvEn;jc$}h>lHc4$P}x#_*r_Mo@u( zeONk*upO-GFH!ZMUHNK7@xxKtIzrDu8v}snl=lb`Ax~rNNDAs=^VR6*lcC>hJDpIo zYS}MwE!o=Ip98BJ!DCq)CBWfkIl8(~d}pOE~@4;kZF_zI}?5U0lqtgaWZ=f%+00 zrpE5<1aC^nha!yOn!hBD(XKzjLk`_>N~bg9LKkVQfA>L$R~}fOcq~Sn>@ztB(4H*? z5;VEtropN8=AP*HWda-RIkbj5D3b-%z0-r#zeNQtp_m^*71}wD{h>#P=>SY{yKH!G zeO{eEPr7pu9A2Xk*(m^Zl8PBRf^&KNTFKAP+Ypw=syFLFr<}}W7PjzhdwF(rlwX&A zgkUpRFENZGiN;_feoOd1YC4*A7*WhiWpZh`4hx~+-$MT|_+DP6o%~DvWn-;>C9MS#)2}r=w+7X|8Zf7t87SGOHRwJcn;}Gj zWhQ*8TPuDOr4uT;!-w2TBlSy`ses9V-o2bzez+|=nS!Vd0h`JXgCge28<_M!%+888 zU}$*bR$t6*Q<$g?zL|lZ3$5#aE17IaN==2H)Fw`=%M5HFRoA4MQ!GpD1h(OV(dauD zY<^6K@OsgfPG!Yq`n%O8GZ6=+?X3_UQ;fDEXTD-r&{UoF{qJi!CHnXQZ}iMWnsbhf zZrip}?We0dG&-XUT(My4f5W%*IX=S*&=Hu3npD+y3Y}XcL~w2j4X!^D!@WF+RJs^ru!7y8U{<;u??x3NldJY4KARjLmi;m;fHFwOW~y^t6Z zcrqC~6GBCL4g7!*<)|TgQ9Azhxa!Cz&oy9(s?PU@Fk^dovtkKwiJjy(586N3aw%tj z)aG^(6?O<>vJYS%HSWV0|44j2pjQOoj`k8_Qh^rqr;L0=w4@_LTilmus3^XWiVou! zkmR1IpM{Q_)HSaZ6#m2+1N_F2gjOi8i>|+iMAiceyimHRb9eK+ShKQ7m>9J=XIU%D zEX2*;YPCI%ZxKC%eBh#}YRCMj`!xo)P*=&BS!ytFuE_KMu2finyEc2NqLeoNU2; z`_8!_-=fN=T~J+0$mqkVNIA8^b&l+BfUMn@{k~qoXsbs*2Eog~a-_F=%)l z5zmsStG*?eMu%nq&jCjnHdGy@p$ol;R=1eZh79d;E6hQZq(AW49>?QX;oSM`*2b74 zV#+dK0uR2#F~9hrcLU*7-p8QdA#_lPo>H)!j{>spcuS76K>~w5ru%PHV2`yhEjth2 zP-L~3kKR5^szbuKt=dlY4+%49x--ykkV{x`HdoNS(n-qM+~qA2ORk?f{QaIki2B4XK%lPyHZI*OeQt>jhCA+D8i0K!0-ZsfEp>|ZEfRfHNZ-Oxm z1=aP6lTXMdGyrK>g>8Z*suFj675fC(akG-I^}32vmW?s zqx=%1?518JQ4~?7K@ld$HLLLLhMiaFmYwC*VSq@mOj^iX%pv79V?p4|MqoAR-!)Iz z)4elK{CfZQQ#osE+rVG|C2w`U zv^Mqm2F4#@`og4i%F|<&+hxlp!S`LW?mimaRPU_9?;R2glHs!hb^yzr8=1FanSU8_ zen1Dhr?P8s@wAjYbc>3QZP{R&cwK$(O2ihGsM$H4<#&^-^I}u4-k$?NcX5>p|3T1(&9 z$_kw=A3_|W7Rg+_aV=X-iR`tN;2pE=kGSwH=Hyey)#j||V6p3O3}zFP?D4;K5~xbE z>nvT`qSd55zy8qPV*Xi0|ChVT<#1$#TeFncc)dJpY!VjGY-B}f$f)d^cd)Izxiaw{ysT@(+k};_~%A6K;PVZ3$X9E}HR~zVuUdyQ#j~mw9X$zj?FTC!mh) z!5a=UWlgG5crzHnz_pJW<~D08@1rdIo-Rf-#ND=X6bd_^Ugv6r<8f-3#Ph#nvp%Lij*h<{X1yXda#AiOanmPM(crq10+;pn+ z1=J>o8T)1@U_~7lCu{r8)Xof*iAfxX+$*- zZG!4!X!(K!mx|a~pv#i73kgNZ7T+Aej;tS)SOLe*8Jz26j|;-o7hfWpdBrT2?$ZXn zh6C=L?EhXr@#`*!^1@J1GZLHhGU8nQj{7MnumO|$voDo_|8XRs-o^(H2^AK#L_YRt zrL|CpvTL|KE;E8&MFEJHH>|Ds!ypU_=fs{~X5fP*q7G3~)f|B`NQtkeapY7vg-kRk zES{Qb?IPyC_-{q`qE#)gMHhVmFnuiiKU!3*t*!lECJn0ZN1_G ztoY^a5aw*Q3QUK0r6~SmU*z(wau!XkIz~qa*`K;-dw?T@Zv?Qu>EB%w&QuIiUcm2Z&e%bFs%n z-;mpsB`|jkhB@yzaAm5P|9hiPmR)k&ZhHLAAiR-UW~-jK1xf5$WFdwfW1{O@yN*v< zp`Zi0hwmN3_Rqhmj3{@z${l-K0}-xhL&u0aLAohzQN~pc65kC;|4iwNI}@I{If7a} zL&DeK(sUUr8?h7St^d^;Of_-K$VI9kDrja9j2e)b=-?^WQUS5mm?R@*2~6%^tw@m5 zqu&MrDXTjDc(~T9J_93*_yZIl=I@<@V^ZN8MZzhon#DyOuu3BWzl5A|5J$K*tT6^= zcupwuZZ1&;G;>pBH(YQkIifKEBvGoZ32bWxyb1ie;`6$pF7g_>v2anH!Z?Td5~kiP zwo3y9eSZM@LMtRQXD$cSRz>C8P^4V7L*_*+c7X`v3Ma{LS^#-D@@%FkRjq``rF%DG1*Y&VCcJ%#VT@(Gf}iAM z>jo?JcQ4p%}p zIOqr7cSLt^rI|>MqcAuXld`1Qf;$C^yC43PaF)laG|w%ssKMH>bJW69w%>`&L4#j| zl_IBJGis+QrF$0zZxUTvvrft!`DY1D|Bi4LUxE)!Wkm)86To28;L%3r6iuFj`ZUX* z%N?4%bRgjhXxkmcj9zP6ywHsy39X2I_{I4vg24WE9fIpi1Z{kl%IR0V$ilw-jUN2W zL-k+3B{04)0={@CFX5NJx2+UaHm_BSlV)Dc(>o?$hO(Nw-!u z|CZHPqy97N-#Ud5qlVfyB}#3z$gL&KpN}BIj?i+?%m`~yMByIa@fYJHD>{$s?eP19 zuSm(^j4gCQPF^_iZ0M2@J{~#M$nZWsUYlBA&>Nz8DXm7kx2!`k`+1=c$Lbf777G{a z5&s*?Nxr#pxW^A{3(i+_+95`Uw$V}AyVU!j9|}dLexr5KyDZ3m6ne9}1j2NDpI<75YiwoyX_ZD%HI56O z_rEEgS>E|D^<>R|)?n!8Vn!K&4$R6dT92C3hgUQ5{2buhZ5T_ZV(ph|SHia3 zyA}$7%yBn2C*BAgvf;)^lf!J;qtNd%XD!YCJ#2Qqt{{M~(@)1t?CcCqa9^i#96$+q zg(L6JWPYB(BIXCJ0n^p_V+?+*+Z~xU(vt`X$je$=p6}zMcw#Dj!)5q2!65D!EJ7^o z$8Kv6(+wqUmg7pHj+G4BTVtSLv&rNJDp;9}Nb;GD400fx7fZNt2ivfT#Hu^sOnaDO z5M2d+7;$gF+L%GxS|6SBn+Zt22<%QNiQ#cexMHQe%&6B70!;^U@a}?9dUl;P$#IdtkjMvcI0AUJ<~>{I?K&qz zdyWE?+GcxabM|;hm(Ir}S_O$(=_I}YH@;qoCkF~cjQkO|p~hU)Q|(UabKP6f=uq_r z8Y&@tFW}Dq9tJe@Ql9N< zxshmHg*DCtCS(8nnn(=g2qDEtKTe(bZL+##1N==O0t4JGM_KnVQY1{!F5>Yd%6r=% z1GS%is|E_7yF!=85~4RfE?befGg)aFhH;u1O1zp{tm*Mbsg%nUiY$0CJsM-Z!y0Ix z;Nyr?IpHZ=YiNpU!vEgrg&?tVNH!QdaYd_kXl#pB7qWEtg<%v>?^-TeA5#BeF{RB{ z&ephp)CbwWfvOOlz~_Lk+67(r@%!F8JRCGhAldHvN)+63ZMd+i=Yuy9_P{6kt4UYl z^g^dkWVgN_r0R*q8d+I2XRK$dpw%IdDHlW2A*nLDBR&#xRLW)}0s-Qf&joV=6i zyFh_^78E$hB0)Z(<8Jq*;^}%pQwQm_A0^2li{8j|2)uV?-WCqAgN=3sF*rvuV4%L$ z2F}QG(sd?Vue5g;<4ZJGz|7->Pr z=*N_i;b`eo8`S_MMr~pufzMG3Z4MJ6{$~|Hq}di0$Nb@SWYlCM2yw6rSl!;@Y627- z92J4%(lQKZDE8gG+w`&fZ4u5gYs+K%i{%}I%M*@vG?b#?GZt>f!WdZn;wp`%Z91Jl zbc))0H2aUdnu7`d|76dc?x_>X<7|Luk-lRu}>1YtOT)AT=vY>V@J zn>VRIGkimX^FOXwQ12$y2C?#Wz4q4>oI|6Vn!G@93JeAP&{Zf9KR!}&Z)@ujrcc$e zRAhjwD|RENI>n_m?$yo_2rjC)7zUg;kATMUnY(#ctj>^_loPR%1_wR_r6X&gpFS+Z zJ>O}KPscJthudrBxk_);dMqB-Q9jR7zFJt zBg}q}dQHozB_|gt0Kaeu4fNf;FMA+2x3BA~}6`@7&%hx@~SelC>!nc#W)(!??p&H5eR)j4r9TcfEg%?&-+})YT!32eIOQ!?j58Xr>V69A)4Aga4w> zU9H%n%VIfYX#IbwOpS>0Q)AUSl8#d4C`dVa0BkEKFbPHAJ|HQ4`$?dHnXN6Ypj)!i z8z02~2qphNau=XGmz%!0GsRuMB8pl7L^@66SP||5JeiJ^A|*nS2Rzpn)FM}=etR8F z!o}=>hUyjXcAXyVWyTu}G-cou=V-$|li=%}y&))ty}yf9Q$Q1zp@A7Tblps1m#uwz(5_4Wq?BH`ti zh)iL!wmLF&K0$8kwDe{qhjsXyy)^0JTAf%OY$^=i-HDWm9e%r)_u%5mmO+lO27bKAj?>8FvweyiKm|}suS>zE z)E}?+xTk4CmBqSq{liG&z?xM_YOj{%IqnR6PGUoEosjf3SHZ_ZZ~@IXl4a*JgypqS zZHsznH%bgGwHpD^C?HzH=36=8VEzJZwekKg3LQQNvD`fi+|YzABt{%- zZGxU~VixWRS^y|uATPglH#;94EaoC0cp|H!AYYYM%y{Z^vH6JF`UZ#}BIGePF#knb ztJW;3mKgD``u5e-89NL9TP9LDF7B_jN9?3VyRddvfuY<$A~LiuAV3o)`scYt_gntw zuBi0W^=jT2a(rAMy))6{yBh>uWdOFVx4Wqwa!)i&WeTEtP|Gt z^KKgMJem`h)MRx*hD_m$pnP0cX&ii!yXNMm@YxCXjPt5s2X~G}B;6R9m=o@~@`HqN zb1VHaeZEO zbTuuyIUuoViz@|oKB$EmqSrJghg{kVTHy3awAXT=9ohLn1X^OF47lEc23RG1A zDU9XZf@VNyZ2XTOPnLf32!297!kw%H(SynrRCJ|MO~H9boDUpJr8Ei=qfh+4BYHDP5)YpK+Q>4iNXn?@br0QL4~!&q3AaQ^YZ_Kp(L~2Z+G1rJJzZn z*Cy3DFv^Rjk)Bdm*@9B?P2}kIMc|iq3srJRM2~G%8MyAuUSi_){HA~OB|~&)H_f08 zjqSot!kG#7}#pw-aCZ6ZI9Kdvu112m>j(U|$Ej3p_o<*o2_O9uTR0Cnk37 zdwGRFXtzbT?NLB@QVw{WqCMzU+N```zkdjk`JfBg&N$5KeiyR!6pkFb(s!rb9%0hn z?^WSS{N|JQz%IqI!6iD9T%~QAdMkX?*#bS|1T|@exPSb`hJin3s+yR(vUGp++zh;L z3{AApL84=(BqKUNcL;ft*N8xLEH(Ih+pFG<&HwpP!PmE$l=Y5m^mo;<+4!I_|H>Q+ z*cb`T_ML-k3-@tl`PW7Zdd0ZX+)NK*6SR`XhxC$p?qFg3Q?V;pB!gfjZ1mZ0?a2Tt zPFs)C^u=~cuN8qS7*b6V(qoiw(9V>(d$={h^6f{Dk>jY4&;{meS9ZPasi{8pJ_6l$ z$lkT&zztm@MPLJtb8#@aqoVji{498RkU%lJ32T+D4~}c}nL;%&&f)dkga`-5$q2oD z{TI2@?8vtEm!S_dwg|eZ!43D--K@-Fb|w8EJ+HrDlAlecnvL5RszZO0*@*i7sJ67? zkJSkZ1(ya1h+g=8z<$>Ox!?_rj2JvSr{7UYDvipSA1oIxxssCR&IJWqIM(C%Q1FgI zdyJ}D+>%jMj6)f)LS_^QMi$p-a0F}vhhf^q3{vBk{y{z>8np~zR|YLsoe+lk?Hg@# zlU1-_&_fd?#sy{2{qX0_$1z=^6K1g7s$>6O zSPgccX4pz)y5fJyKZ+v-!Tu0qD+=A0cSLwsbL;!uh!&!BlX-gpXiQJNn=T=H1Lb%1 zL&lYpHT=VA-|k$X!*ittC$C`_67tdP5R8$?*VvJ@>^YS9TeIC$b7+|=EpEI+atj$i z{eiL~l6%l91fOU&;GF!@I=l;hxvIU-NKHeM#YyaHrbf0gFA5Qi^;Q1VP1=gC59+CyKM5EcU5Iz zXavTD>j0YX{R}U6TrX~PtxkkRw58c&yKziI-KdIBoWv0UlC}!jGfIKJP9`Ic3k+N+ zz>j|@GEna$%JNtA(_XgcPJebbZ{moh+owPDr=JtNGPk;2fi!r`(F`M`j%37qJa@_| zl-Zi_s_%|=%jHg~{j_wm!P${O0w?qNqbiqQNlUgXE0+t@Oeu6iLd9pN7CU$mB9K!_4h@zyY$h*xna=0!nH zm8pQ9LCix0wy=V0!!;ps88&qSR&79HK;PvbQ3i~Qs{pkSIFltU&k$VFf%M(xa;}Po zfJ+d<{^jMu-QBPG0xvh1iNo~;u3E1R?R>R%xCPnt$5iewmTKviK~z!`Gj^*( z&958lhmMhLm7|O#Fmu|(RRxv2cZ-%ufuqO|z zWZiJ7Paax#nP+#s?;n7X`K+9PKk*CF;2b5@%N2?267vcM)^5Q|Y&o+8ieVq~feXVu zvds2UR=bp2?stM)^?4Kazm)y%hR_)ToF-Y)?XEMBSe`W!}c@rwqScopzWzw!81~3n0rzbhe{{b6_SBVcyXP!ZXRyp zEBmaa1t%aF_-7(LC4|W|iJwQZg{$-x2)_Vzu9E4oWI?Q}(E=@kR!-#@9CpncXN(!odHi!m?6p*y+>7h2(P5?js+ zs>IVZ<7QaRZt}|Y3d&W6AN`c-$wZJf%3>u^x53S!#3v#<2r+FsA6T z)H4LjY0(pSsOD1{iQ0t~wPt2Lh}}i<3B=ZAb<2!LjM~^ zptsjgaGq6w7!tO>*)KyIyI@W#lJKPu5aRuhE?|5dTGY@%H3`^U5B{|k=cjqXGm(`y z>&(oJ%e9j$0kxUV;5W*5$>;lZB zHkk(81c?z^sl~meXmn#!!x<2I?HNwBO#|&;NCc#oR#JLW0@q+?uF$xD;1?Ad2G^d! zaku)2(Pl@X#z1=cZgneQvXs~>f;=w+2+iQ<6lk4 ziS*#_L1>4B!xgnTM>x=026&Lw8kuYpDDG4A)j;uzJC-+2Fkq zqpxafT~xxLEXsmHt=ijUq*3%P>f_U)A_tYUfqu)sUC2~v#@`JQZcwDW>d!53 z=v$MVV6QV8ZpsK#=^0RUHt=xL+bO8oF$x1&kB`cl2rN$FZw}L#+h<;&uY3;}gdets zyiR&8GLB`MxD}!yxpDBS$o90h19#p-X96asL|(BBU#^9`Zpq?z!_;QI{K4y8+8=yv%)7hNql)&#-SH*Gt%W!*)8-KFFD4rY zV*G1B)Y{^P4~pcxQ?i+vq`)>SNS`%9X_M{TfKf7?@0n*{G8K)U-k{I!yDuO9*AKv9 z>2ycn(C7fshnc0>G&b9Qq}4~{@kzJLRX5%pwE+LkV?aGu;@?S7KteJXIjiAYto8W9 zvcN|Fh5-sbGE)RK1;UMUNKYyhNh2vT-K9eUPiwL40kjqVB-bJ^RX#SY)#Jo%ltR3) zz@`^vDvWH3+~oQc8a)!JHMfMGg)V!^-axEIYyL1h)Cvw}qe@jGtdO1*aA<_UX1;X9zre?9)U!~X8!bv(vwlb&BXa@P+I1Xs18 zDh5)zg{Xx8PXLq(YxSHP1Q!<%czN`amX2!FmsTLYJOoo#t-`hI*JAD31(;95o-!rST`3QIeSo2RE?@LH$QN$W-ea* zbu`^?EkasuDH?4Z5im9aekA^uu46G}Vi?>lYmt|J8bvf+G(7)A7Jo@G3i8@eA21VR z18pF&w}p+JH653sFuxcwwT3#h67A(BD9y?RTbexQVb$~D8G*24kTN-CVzk#qp@Y3-=6q?s0_*{WwRqy7PxF_<_Z1g@5KD9lP0mQxJn$0^t)8iN$^`C{4^jNliOCjMb*o zDA8JyfRvM`kx|sWjsz&a=CT|dJ3;Nf-FOYc(ajSPQ|7_nMg@^l!Xf?Tp8nhmL7hlHLquF%=7A=|qAF>`S>E9WP79qf*7>VD%jyL05QQg4K zNyfo_@z{P;3h(PTU}dNSeC<5o9^eTV_f8bWA4OhcBkEd9k#gh!_WgPYWpw#LiND(n z%wD<#3rDMQ__e>|yVMHg*U`0e58}j*uke50mZ81N*s>+=aPhImXo~|#Jkfx%a+bz? zWTqX($L}Nxo23nPHE3vV>ElUCbKDRZ7Kwl`FI1FOB4);TgnE)CW;}X%afOSUgoM2Y z2eZ?&(*8rK^0k)2lu;Px%XixnGySHt};W8G7!KMB90$%^yL-^aPTX3Y2 z^t|74G{eIOzV7XCktQP{fo361EY3_EKXMZLb`-$ILW|1saY=?5%&{$BZfz)Kl2}c%0g^1<(FefsQjzdHKROWD=IF3q|&4uj1GE zBqUcG>Y=H&90~vXJ)V5{alH0rJW_kUoufVtsaxN{efPb9FOrSdV0Bngg{IRPIAJpi zHa;$J8|Wq&XIL|E@$V=>Yy9*0-J;o;HE9wincR#;m~>wvJXXJe|9kvCY#3z><4< z_uYFR9-pbf=l4&-ycz7ATk&$H1d)&b8+#s^B0QYKEauqNH)7*mi!g((@dx1=*Wi`J zc8HeVixm`NV2?+gMH0Ij%kO#wZ{OI2Ee|ilb+hQ&t6#?3`+)}@SOF&|;})DG7SYpI z;h~$oaP;L>xN$K{>_vj;ET;t8jdUt#~QLtqaji$v#NVU`4iBW(0s#M#7R z;nZMwx(znvLq|YRG@?gOg&mplOQy!bo0-nNAs&s$$;)x?I(HZqW0@Iu{((dt1G-5VQpiFiBp#dca%j31z_rEwjF&QqSxTAJMYA!(==vzyBDwL zh!OV43)p)9M0hwEh7R%Q69nWql+xx|0 z)W#R_{(~;4`SA%naIK*p7O%Jkk9{){(;j^mk375*vwQCR(@cEU>Ra&ngO1qt#0JAP zSRG#fFm8Ld9oN0|FWkB$7NfcN|0WpFE1hMvH1#jeK~9~~qZ@4ekRWW*1cdmz3-{f3 zLspC0ieel$JK4b}f-K}1#QK@v10h3uZ3POB=b)OtF-zYyC+AGqLP|#+4w~hnEVle^(?NCtAiNJAV zg*1!Ry@c}$MEJN!I8+=!Zk07`{Gt#R<4eO-J@O8uLmfI9zCmPV^?WL+pK7!}p zQ{kb{AHnoMG28~Z+dKGIIxEmxUWoFVRy0UPV{W7y?AXG3XC3ORN|96|h0oZzi1f09 zn94=jQICe=WMp-QWAx}i__{g3va1E{m6ImZKbDB+^8e}vt=ci5ymA@fI>=2+Ni=t{wslAN)CmZrj^!}G!JEI*d3ZA*@#hR2dC_*nA5FyD*>mup zr)DGA#m?->&Vey_@#kDDgA;$wK;Ys(yczhi52tU~6PxlX1-frFXICL?b2;#hdv z(Tu?ugu~%*h7(-;hXS1vXgrK>U-}!KdN&Qn6f^MPGH*EZm!NPsoM8$V|DnLr9`IX@ zhu`}SJGQ@t_a2@LKjv*X%HeQ0!wxR~LxKpfa)PV3AN&Kn;O*)#3|=|F;cz&8!^NM& z;c!ME{BECNi0N)0zkpx_1ct!TiQia#sVU6Q5+3G@8Wk)2po_(Y{lGED3|6M?ZLOF* zZI020Go0Y!KMav~bz$%BpWz=E1{c@M^)Bd-4a;9?UC8Ip>3y>F|b&|1d_QQB&t(PjYfN9L`Vz{6Cc{ V9uT39qY?lB002ovPDHLkV1iRtx-9?z literal 0 HcmV?d00001 diff --git a/doc/source/_static/extensions/icepak_model_reviewer_ui_with_table.png b/doc/source/_static/extensions/icepak_model_reviewer_ui_with_table.png new file mode 100644 index 0000000000000000000000000000000000000000..41690962900960800584275a04c41fcd322c726a GIT binary patch literal 80838 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 literal 0 HcmV?d00001 diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py new file mode 100644 index 000000000000..3b7cc5422e4c --- /dev/null +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -0,0 +1,342 @@ +import tkinter as tk +from tkinter import ttk +from icepak_model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file +from ansys.aedt.core.extensions.misc import get_aedt_version +from ansys.aedt.core.extensions.misc import get_port +from ansys.aedt.core.extensions.misc import get_process_id +from ansys.aedt.core.extensions.misc import is_student +from ansys.aedt.core.extensions.misc import ExtensionCommon +from ansys.aedt.core.extensions.misc import ExtensionCommonData +from ansys.aedt.core.extensions.misc import ExtensionTheme +from ansys.aedt.core import * + +from icepak_model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ + compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data + +port = get_port() +version = get_aedt_version() +aedt_process_id = get_process_id() +theme = ExtensionTheme() +EXTENSION_TITLE = "Icepak Model Reviewer" + +def flatten_list(mixed_list): + flat_list = [] + for row in mixed_list: + result = [] + for item in row: + if isinstance(item, list): + result.append(",".join(str(sub) for sub in item)) + else: + result.append(str(item)) + flat_list.append(result) + return flat_list + +def expand_list(flat_list): + mixed_list = [] + for row in flat_list: + result = [] + for item in row: + if isinstance(item, str) and "," in item: + parts = [s.strip() for s in item.split(",")] + result.append(parts) + else: + result.append(str(item)) + mixed_list.append(result) + return mixed_list + +def add_icon_to_cells(data, icon_indices, icon="🔒"): + """ + Adds an icon to specified cells in the data. + Parameters: + - data: list of list of strings (table rows) + - icon_indices: list of list of ints, where each inner list contains read only column indices + - icon: string icon to prepend (default '🔒') + + Returns: + - new_data: deep copy of data with icons added + """ + from copy import deepcopy + new_data = deepcopy(data) + + for row_idx, cols in enumerate(icon_indices): + for col_idx in cols: + cell = new_data[row_idx][col_idx-1] + if isinstance(cell, str): + new_data[row_idx][col_idx-1] = f"{cell}{icon}" + elif isinstance(cell, list): + cell[-1] += icon + new_data[row_idx][col_idx-1] = cell + return new_data + +def remove_icon_from_cells(data, icon="🔒"): + """ + Removes the icon from all cells that start with it. + + Parameters: + - data: list of list of strings + - icon: the icon to remove (default '🔒') + + Returns: + - new_data: deep copy of data with icons removed + """ + from copy import deepcopy + new_data = deepcopy(data) + + for i, row in enumerate(new_data): + for j, cell in enumerate(row): + if isinstance(cell, str): + if cell.endswith(f"{icon}"): # cells can also be list in case of multiple selection + new_data[i][j] = cell[:-(len(icon))] + if isinstance(cell, list): + if cell[-1].endswith(icon): + cell[-1] = cell[-1][:-(len(icon))] + return new_data + +def add_table_to_tab(tab, table_data): + for child in tab.winfo_children(): + child.destroy() + headings, type_list, selection_dict, row_data, read_only_cols = table_data + table = Table(tab, headings, type_list, read_only_cols) + table.pack(fill=tk.BOTH, expand=True) + for column_name, options in selection_dict.items(): + table.set_multi_select_options(column_name, options) + row_data_with_icon = add_icon_to_cells(flatten_list(row_data), read_only_cols) + for row in row_data_with_icon: + table.add_row(row) + return table + + +class Table(tk.Frame): + def __init__(self, parent, headers, types, read_only_data): + super().__init__(parent) + self.headers = ["✔"] + headers + print("read only data") + print(read_only_data) + self.types = ["checkbox"] + types + self.read_only_data = [set(r) for r in read_only_data] + #style.configure("Treeview", font=theme.default_font) + self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse") + for i, header in enumerate(self.headers): + self.tree.heading(header, text=header) + self.tree.column(header, width=50 if i == 0 else 140, anchor=tk.CENTER) + + self.tree.pack(fill=tk.BOTH, expand=True) + self.tree.bind("", self.edit_cell) + + self.rows_data = [] + self.multi_select_options = {} + self.selected_rows = set() + + def set_multi_select_options(self, header, options): + self.multi_select_options[header] = options + + def add_row(self, row_data): + print("adding row") + print(row_data) + if len(row_data) != len(self.headers) - 1: + raise ValueError("Row data must match the number of non-checkbox columns") + + full_data = ["⬜"] + row_data + self.rows_data.append(full_data) + row_id = self.tree.insert("", "end", values=full_data) + + def toggle_row(self, row_id, item_index): + if row_id in self.selected_rows: + self.selected_rows.remove(row_id) + self.tree.set(row_id, 0, "⬜") + else: + self.selected_rows.add(row_id) + self.tree.set(row_id, 0, "✅") + + def get_modified_data(self): + + return [row[1:] for row in self.rows_data] # exclude checkbox column + + def edit_cell(self, event): + region = self.tree.identify("region", event.x, event.y) + if region != "cell": + return + + row_id = self.tree.identify_row(event.y) + col = int(self.tree.identify_column(event.x)[1:]) - 1 + item_index = self.tree.index(row_id) + + if col == 0: + self.toggle_row(row_id, item_index) + return + + if col in self.read_only_data[item_index]: + return + + bbox = self.tree.bbox(row_id, f"#{col + 1}") + if not bbox: + return + + x, y, width, height = bbox + abs_x = self.tree.winfo_rootx() + x + abs_y = self.tree.winfo_rooty() + y + + item = self.tree.item(row_id) + value = item["values"][col] + type_ = self.types[col] + + def apply_to_selected(new_value): + for rid in self.tree.get_children(): + if row_id in self.selected_rows: + targets = self.selected_rows + else: + targets = {row_id} + if rid in targets: + idx = self.tree.index(rid) + if col not in self.read_only_data[idx]: + self.tree.set(rid, col, new_value) + self.rows_data[idx][col] = new_value + + if type_ == "text": + entry = tk.Entry(self.tree) + entry.insert(0, value) + entry.place(x=x, y=y, width=width, height=height) + entry.focus_set() + + + def on_return(event): + new_value = entry.get() + apply_to_selected(new_value) + entry.destroy() + + entry.bind("", on_return) + entry.bind("", lambda e: entry.destroy()) + + elif type_ == "combo": + options = self.multi_select_options.get(self.headers[col], []) + combo = ttk.Combobox(self.tree, values=options, state="readonly", style="PyAEDT.TCombobox", font=theme.default_font) + combo.place(x=x, y=y, width=width, height=height) + combo.set(value) + + def on_select(event=None): + new_value = combo.get() + apply_to_selected(new_value) + combo.destroy() + + combo.bind("<>", on_select) + combo.bind("", lambda e: combo.destroy()) + combo.focus_set() + + elif type_ == "multiple_text": + options = self.multi_select_options.get(self.headers[col], []) + top = tk.Toplevel(self) + top.title("Select Multiple") + top.geometry(f"200x300+{abs_x}+{abs_y}") + + listbox = tk.Listbox(top, selectmode="multiple", font=theme.default_font) + for opt in options: + listbox.insert(tk.END, opt) + listbox.pack(fill="both", expand=True) + + current_vals = [val.strip() for val in value.split(",")] + for idx, opt in enumerate(options): + if opt in current_vals: + listbox.selection_set(idx) + + def confirm(): + selected = [options[i] for i in listbox.curselection()] + value_str = ", ".join(selected) + apply_to_selected(value_str) + top.destroy() + + ttk.Button(top, text="OK", command=confirm).pack() + top.transient(self) + top.grab_set() + self.wait_window(top) + + + +class IcepakModelReviewer(ExtensionCommon): + def __init__(self, withdraw: bool = False): + # Initialize the common extension class with the title and theme color + super().__init__( + EXTENSION_TITLE, + theme_color="light", + withdraw=withdraw, + add_custom_content=False, + ) + + self.add_extension_content() + + def add_extension_content(self): + # --- Top Button Panel --- + button_frame = ttk.Frame(self.root, style="PyAEDT.TFrame") + button_frame.pack(fill=tk.X, padx=10, pady=5) + notebook = ttk.Notebook(self.root, style="TNotebook") + notebook.pack(fill=tk.BOTH, expand=True) + self.root.boundary_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") + notebook.add(self.root.boundary_tab, text="Boundary") + self.root.materials_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") + notebook.add(self.root.materials_tab, text="Material") + self.root.models_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") + notebook.add(self.root.models_tab, text="Models") + ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton").pack(side=tk.LEFT, + padx=5) + ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton").pack( + side=tk.LEFT, padx=5) + + def load_project(self): + print("Loading project...") + + desktop = Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student(), + ) + + ipk = Icepak() + data = export_config_file(ipk) + print("config_file_exported") + #print(data) + self.root.json_data = data + desktop.release_desktop(close_projects=False, close_on_exit= False) + # --- Tabbed Interface --- + table_data = extract_boundary_data(data) + self.root.bc_table = add_table_to_tab(self.root.boundary_tab, table_data) + table_data = extract_material_data(data) + self.root.mat_table = add_table_to_tab(self.root.materials_tab, table_data) + table_data = extract_model_data(data) + self.root.model_table = add_table_to_tab(self.root.models_tab, table_data) + + def update_project(self): + print("Updating project...") + desktop = Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student(), + ) + + ipk = Icepak() + obj_mapping = get_object_id_mapping(ipk) + bc_data = self.root.bc_table.get_modified_data() + bc_data = expand_list(remove_icon_from_cells(bc_data)) + differences, new_bc_data = compare_and_update_boundary_data(self.root.json_data, bc_data, obj_mapping) + print(differences) + mat_data = self.root.mat_table.get_modified_data() + mat_data = expand_list(remove_icon_from_cells(mat_data)) + differences, new_mat_data = compare_and_update_material_data(self.root.json_data, mat_data) + print(differences) + model_data = self.root.model_table.get_modified_data() + model_data = expand_list(remove_icon_from_cells(model_data)) + differences, new_model_data = compare_and_update_model_data(self.root.json_data, model_data) + combined_data = {**new_model_data, **new_mat_data, **new_bc_data} + print(differences) + import_config_file(ipk, combined_data) + desktop.release_desktop(False,False) + + + +# === Main Application === +if __name__ == "__main__": + #main() + extension = IcepakModelReviewer(withdraw=False) + tk.mainloop() \ No newline at end of file diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py new file mode 100644 index 000000000000..e0c1b25c8f10 --- /dev/null +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py @@ -0,0 +1,36 @@ +import json +import os + + + +def export_config_file(aedtapp): + aedtapp.configurations.options.export_monitor = False + aedtapp.configurations.options.export_native_components = False + aedtapp.configurations.options.export_datasets = False + aedtapp.configurations.options.export_parametrics = False + aedtapp.configurations.options.export_variables = False + aedtapp.configurations.options.export_mesh_operations = False + aedtapp.configurations.options.export_optimizations = False + config_file = aedtapp.configurations.export_config() + with open(config_file, 'r') as file: + data = json.load(file) + return data + + +def import_config_file(aedtapp, json_data): + full_path = os.path.abspath("load.json") + with open(full_path, 'w') as file: + json.dump(json_data, file) + print(f"json file path is {full_path}") + out = aedtapp.configurations.import_config(full_path) + result = aedtapp.configurations.validate(out) + if result: + print("sucessfully imported configuration") + else: + print("import has issues") + return None + + +def get_object_id_mapping(aedtapp): + object_id_map = {name: aedtapp.modeler.get_obj_id(name) for name in aedtapp.modeler.object_names} + return object_id_map diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py new file mode 100644 index 000000000000..916eb7c7d5d5 --- /dev/null +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py @@ -0,0 +1,378 @@ +import copy + +def extract_boundary_data(data): + boundary_data = [] + object_mapping = data.get("general", {}).get("object_mapping", {}) + read_only_cols = [] + selection_dict = {} + headings = ["Boundary Name", "Boundary Type", "Selected Objects", "BC Name 1", "Value 1","BC Name 2", "Value 2"] + type_list = ["text", "text", "multiple_text", "text", "text", "text", "text"] + # Convert mapping to ensure all values are names (some are lists) + id_to_name = {} + for obj_id, value in object_mapping.items(): + if isinstance(value, list): # Some entries have extra data in a list + id_to_name[obj_id] = value[0] # Extract the name + else: + id_to_name[obj_id] = value # Direct mapping + + all_objects = [obj_name for obj_name, obj_details in data.get("objects", {}).items()] + selection_dict["Selected Objects"] = all_objects + + for boundary_name, boundary_details in data.get("boundaries", {}).items(): + cols = [1,2,4,6] + boundary_type = boundary_details.get("BoundType", "") + #block_type = boundary_details.get("Block Type", "") # Solid or Fluid + if boundary_type == "Block": + use_total_power = boundary_details.get("Use Total Power", "") + use_external_conditions = boundary_details.get("Use External Conditions", "") + if use_total_power: + bc_name1 = "Total Power" + bc_name2 = "N/A" + value2 = "0.0" + value1 = boundary_details.get("Total Power", "0W") # Default to "0W" if missing + object_ids = boundary_details.get("Objects", []) # Default to empty list if missing + selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + cols.append(7) + read_only_cols.append(cols) + elif use_external_conditions: + bc_name1 = "Heat Transfer Coefficient" + bc_name2 = "Temperature" + value1 = boundary_details.get("Heat Transfer Coefficient", "0w_per_m2k") + value2 = boundary_details.get("Temperature", "0cel") + object_ids = boundary_details.get("Objects", []) # Default to empty list if missing + selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + read_only_cols.append(cols) + else: + bc_name1 = "Power Density" + bc_name2 = "N/A" + value2 = "0.0" + value1 = boundary_details.get("Power Density", "0w_per_m3") + object_ids = boundary_details.get("Objects", []) # Default to empty list if missing + selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + cols.append(7) + read_only_cols.append(cols) + + if boundary_type == "Source": + thermal_condition = boundary_details.get("Thermal Condition", "") + if thermal_condition == "Surface Flux": + bc_name1 = "Surface Heat" + bc_name2 = "N/A" + value1 = boundary_details.get("Surface Heat", "0kW_per_m2") + value2 = "0.0" + object_ids = boundary_details.get("Faces", []) # Default to empty list if missing + print(f"Faces id {object_ids}") + #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + #print(f"converted faces id {selected_objects}") + selected_objects = [str(ids) for ids in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + cols.append(3) + cols.append(7) + read_only_cols.append(cols) + if thermal_condition == "Total Power": + bc_name1 = "Total Power" + bc_name2 = "N/A" + value1 = boundary_details.get("Total Power", "0W") + value2 = "0.0" + object_ids = boundary_details.get("Faces", []) # Default to empty list if missing + #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + selected_objects = [str(ids) for ids in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + cols.append(3) + cols.append(7) + read_only_cols.append(cols) + if thermal_condition == "Fixed Temperature": + bc_name1 = "Fixed Temperature" + bc_name2 = "N/A" + value1 = boundary_details.get("Temperature", "0cel") + value2 = "0.0" + object_ids = boundary_details.get("Faces", []) # Default to empty list if missing + #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + selected_objects = [str(ids) for ids in object_ids] + boundary_data.append([boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2]) + cols.append(3) + cols.append(7) + read_only_cols.append(cols) + return headings, type_list, selection_dict, boundary_data, read_only_cols + +def extract_model_data(data): + object_data = [] + bulk_materials = set() + surface_materials = set() + headings = ["Object Name", "Bulk Material", "Surface Material", "Solve Inside", "Modeling"] + type_list = ["text", "combo", "combo", "combo", "combo"] + selection_dict = {"Solve Inside": ["True", "False"], "Modeling": ["Model", "Non-Model"]} + read_only_cols = [] + + for obj_name, obj_details in data.get("objects", {}).items(): + cols = [1] + component_name = obj_name + bulk_material = obj_details.get("Material", "") + surface_material = obj_details.get("SurfaceMaterial", "") + solve = obj_details.get("SolveInside", "") + if solve: + solve_inside = "True" + else: + solve_inside = "False" + + model = obj_details.get("Model", "") + + if model: + modelling = "Model" + else: + modelling = "Non-Model" + + if bulk_material == '""' or bulk_material == '': + bulk_material = "Not Specified" + bulk_materials.add(bulk_material) + else: + bulk_materials.add(bulk_material) + + if surface_material == '""': + surface_material = surface_material.strip('"') + data["objects"][obj_name]["SurfaceMaterial"] = surface_material + surface_material = "Not Specified" + surface_materials.add(surface_material) + elif surface_material == '': + surface_material = "Not Specified" + surface_materials.add(surface_material) + elif surface_material == None: + surface_material = "Not Specified" + surface_materials.add(surface_material) + else: + surface_material = surface_material.strip('"') + data["objects"][obj_name]["SurfaceMaterial"] = surface_material #removing "" in the source + surface_materials.add(surface_material) + + object_data.append([ component_name, bulk_material, surface_material, solve_inside, modelling]) + read_only_cols.append(cols) + selection_dict["Bulk Material"] = list(bulk_materials) + selection_dict["Surface Material"] = list(surface_materials) + return headings, type_list, selection_dict, object_data, read_only_cols + +def extract_material_data(data): + materials = data.get("materials", {}) + extracted_data = [] + read_only_cols = [] + headings = ["Material Name", "Material Type", "Thermal Conductivity", "Mass Density", "Specific Heat", + "Thermal Expansion Coefficient", "Diffusivity", "Viscosity"] + type_list = ["text", "text", "text", "text", "text", "text", "text", "text"] + selection_dict = {} + + for mat_name, mat_details in materials.items(): + cols = [1] + material_type = mat_details.get("thermal_material_type", {}).get("Choice", "N/A") + # make material type read only + cols.append(2) + if material_type == "Solid" or material_type == "N/A": + cols.append(8) + thermal_conductivity = mat_details.get("thermal_conductivity", "N/A") + # Handle anisotropic thermal conductivity case + if isinstance(thermal_conductivity, dict): + thermal_conductivity = thermal_conductivity['property_type'] + cols.append(3) + mass_density = mat_details.get("mass_density", "N/A") + specific_heat = mat_details.get("specific_heat", "N/A") + thermal_expansion_coefficient = mat_details.get("thermal_expansion_coefficient", "N/A") + + diffusivity = mat_details.get("diffusivity", "N/A") + viscosity = mat_details.get("viscosity", "N/A") + + extracted_data.append([mat_name, material_type, thermal_conductivity, mass_density, specific_heat, + thermal_expansion_coefficient, diffusivity, viscosity + ]) + read_only_cols.append(cols) + return headings, type_list, selection_dict, extracted_data, read_only_cols + +def compare_and_update_boundary_data(original_data, modified_object_data, object_mapping): + """ + Compares modified object data with the original data and identifies differences. + Also returns the updated original data with the modifications applied. + """ + #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + differences = [] + inverse_mapping = {str(v): k for k, v in object_mapping.items()} + + + updated_data = {"boundaries": {}, "general": {}} + updated_data["general"]["object_mapping"] = {**original_data["general"]["object_mapping"], **inverse_mapping} + modified_boundary = set() + for row in modified_object_data: + (boundary_name, boundary_type, selected_objects, + bc_name1, value1, bc_name2, value2) = row + + original_obj = original_data["boundaries"][boundary_name] + updated_data["boundaries"][boundary_name]=copy.deepcopy(original_data["boundaries"][boundary_name]) + + + # Convert string values back to boolean where necessary + print("printing selected objects") + print(selected_objects) + print(object_mapping) + + # Check for differences and update + if isinstance(selected_objects, list): + selected_object_ids = [int(i) if str(i).isdigit() else object_mapping[i] for i in selected_objects] + selected_objects_list = [i for i in selected_objects] + if isinstance(selected_objects, str): + selected_object_ids = [int(i.strip()) if str(i.strip()).isdigit() else object_mapping[i.strip()] + for i in selected_objects.split(",")] + selected_objects_list = [i.strip() for i in selected_objects.split(",")] + + original_obj_ids = original_obj.get("Objects", []) + if original_obj_ids: + if set(original_obj_ids) != set(selected_object_ids): + differences.append( + f"{boundary_name}: {bc_name1} selected objects changed to '{selected_objects}'") + #updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids + updated_data["boundaries"][boundary_name]["Objects"] = selected_objects_list + modified_boundary.add(boundary_name) + + if original_obj.get(bc_name1, "") != value1: + differences.append( + f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'") + updated_data["boundaries"][boundary_name][bc_name1] = value1 + modified_boundary.add(boundary_name) + + if bc_name2 != "N/A": + if original_obj.get(bc_name2, "") != value2: + differences.append( + f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'") + updated_data["boundaries"][boundary_name][bc_name2] = value2 + modified_boundary.add(boundary_name) + + modified_data = {"boundaries": {}, "general": {}} + modified_data["general"]["object_mapping"] = {**original_data["general"]["object_mapping"], **inverse_mapping} + for boundary_name in modified_boundary: + modified_data["boundaries"][boundary_name] = copy.deepcopy(updated_data["boundaries"][boundary_name]) + + return differences, modified_data + +def compare_and_update_model_data(original_data, modified_object_data): + """ + Compares modified object data with the original data and identifies differences. + Also returns the updated original data with the modifications applied. + """ + #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + updated_data = {"objects": {}} + differences = [] + modified_objects = set() + # Convert object data into a lookup dictionary for easy comparison + for row in modified_object_data: + obj_name, bulk_material, surface_material, solve_inside, modelling = row + + original_obj = original_data["objects"][obj_name] + updated_data["objects"][obj_name]=copy.deepcopy(original_data["objects"][obj_name]) + + # Convert string values back to boolean where necessary + solve_inside_bool = solve_inside == "True" + modelling_bool = modelling == "Model" + + # Check for differences and update + if not bulk_material == "Not Specified": + if original_obj.get("Material", "") != bulk_material: + differences.append( + f"{obj_name}: Bulk Material changed from '{original_obj.get('Material', '')}' to '{bulk_material}'") + updated_data["objects"][obj_name]["Material"] = bulk_material + modified_objects.add(obj_name) + + if not surface_material == "Not Specified": + if original_obj.get("SurfaceMaterial", "")!= surface_material: + differences.append( + f"{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to '{surface_material}'") + updated_data["objects"][obj_name]["SurfaceMaterial"] = surface_material + modified_objects.add(obj_name) + + if original_obj.get("SolveInside", "") != solve_inside_bool: + differences.append( + f"{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' to '{solve_inside_bool}'") + updated_data["objects"][obj_name]["SolveInside"] = solve_inside_bool + modified_objects.add(obj_name) + + if original_obj.get("Model", "") != modelling_bool: + differences.append(f"{obj_name}: Modeling changed from '{original_obj.get('Model', '')}' to '{modelling_bool}'") + updated_data["objects"][obj_name]["Model"] = modelling_bool + updated_data["objects"][obj_name]["SurfaceMaterial"] = None + modified_objects.add(obj_name) + + modified_data = {"objects": {}} + for obj_name in modified_objects: + modified_data["objects"][obj_name] = copy.deepcopy(updated_data["objects"][obj_name]) + + return differences, modified_data + +def compare_and_update_material_data(original_data, modified_object_data): + """ + Compares modified object data with the original data and identifies differences. + Also returns the updated original data with the modifications applied. + """ + #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + differences = [] + updated_data = {"materials": {}} + # Convert object data into a lookup dictionary for easy comparison + modified_materials = set() + for row in modified_object_data: + (mat_name, material_type, thermal_conductivity, + mass_density, specific_heat,thermal_expansion_coefficient, diffusivity, viscosity)= row + + original_obj = original_data["materials"][mat_name] + updated_data["materials"][mat_name]=copy.deepcopy(original_data["materials"][mat_name]) + + # Check for differences and update + if not isinstance(original_obj.get("thermal_conductivity"), dict): + if original_obj.get("thermal_conductivity", "") != thermal_conductivity: + differences.append( + f"{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' to '{thermal_conductivity}'") + updated_data["materials"][mat_name]["thermal_conductivity"]= thermal_conductivity + modified_materials.add(mat_name) + + if original_obj.get("mass_density", "") != mass_density: + differences.append( + f"{mat_name}: Mass density changed from '{original_obj.get('mass_density', '')}' to '{mass_density}'") + updated_data["materials"][mat_name]["mass_density"] = mass_density + modified_materials.add(mat_name) + + if original_obj.get("specific_heat", "") != specific_heat: + differences.append( + f"{mat_name}: specific heat changed from '{original_obj.get('specific_heat', '')}' to '{specific_heat}'") + updated_data["materials"][mat_name]["specific_heat"] = specific_heat + modified_materials.add(mat_name) + + if original_obj.get("thermal_expansion_coefficient", "") != thermal_expansion_coefficient: + differences.append(f"{mat_name}: Thermal expansion coefficient changed " + f"from '{original_obj.get('thermal_expansion_coefficient', '')}' to '{thermal_expansion_coefficient}'") + updated_data["materials"][mat_name]["thermal_expansion_coefficient"] = thermal_expansion_coefficient + modified_materials.add(mat_name) + + if original_obj.get("diffusivity", "") != diffusivity: + differences.append(f"{mat_name}: diffusivity changed " + f"from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'") + updated_data["materials"][mat_name]["diffusivity"] = diffusivity + modified_materials.add(mat_name) + + if original_obj.get("viscosity", "") != viscosity: + differences.append(f"{mat_name}: diffusivity changed " + f"from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'") + updated_data["materials"][mat_name]["viscosity"] = diffusivity + modified_materials.add(mat_name) + + modified_data = {"materials": {}} + for mat_name in modified_materials: + modified_data["materials"][mat_name] = copy.deepcopy(updated_data["materials"][mat_name]) + return differences, modified_data + +if __name__ == "__main__": + import json + + sample_json = "test1.json" + with open(sample_json, 'r') as file: + data = json.load(file) + extract_boundary_data(data) \ No newline at end of file From 42cfcb2680e4ded4a37152d340a428350c33cbb8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 08:23:46 +0000 Subject: [PATCH 03/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/icepak_model_reviewer.py | 93 +++++--- .../icepak/icepak_model_reviewer/__init__.py | 23 ++ .../icepak/icepak_model_reviewer/backend.py | 29 ++- .../configuration_data_processing.py | 204 ++++++++++++------ 4 files changed, 253 insertions(+), 96 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 3b7cc5422e4c..37d002fc7b85 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -1,17 +1,47 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import tkinter as tk from tkinter import ttk -from icepak_model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file + +from icepak_model_reviewer.backend import export_config_file +from icepak_model_reviewer.backend import get_object_id_mapping +from icepak_model_reviewer.backend import import_config_file +from icepak_model_reviewer.configuration_data_processing import compare_and_update_boundary_data +from icepak_model_reviewer.configuration_data_processing import compare_and_update_material_data +from icepak_model_reviewer.configuration_data_processing import compare_and_update_model_data +from icepak_model_reviewer.configuration_data_processing import extract_boundary_data +from icepak_model_reviewer.configuration_data_processing import extract_material_data +from icepak_model_reviewer.configuration_data_processing import extract_model_data + +from ansys.aedt.core import * +from ansys.aedt.core.extensions.misc import ExtensionCommon +from ansys.aedt.core.extensions.misc import ExtensionTheme from ansys.aedt.core.extensions.misc import get_aedt_version from ansys.aedt.core.extensions.misc import get_port from ansys.aedt.core.extensions.misc import get_process_id from ansys.aedt.core.extensions.misc import is_student -from ansys.aedt.core.extensions.misc import ExtensionCommon -from ansys.aedt.core.extensions.misc import ExtensionCommonData -from ansys.aedt.core.extensions.misc import ExtensionTheme -from ansys.aedt.core import * - -from icepak_model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ - compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data port = get_port() version = get_aedt_version() @@ -19,6 +49,7 @@ theme = ExtensionTheme() EXTENSION_TITLE = "Icepak Model Reviewer" + def flatten_list(mixed_list): flat_list = [] for row in mixed_list: @@ -31,6 +62,7 @@ def flatten_list(mixed_list): flat_list.append(result) return flat_list + def expand_list(flat_list): mixed_list = [] for row in flat_list: @@ -44,6 +76,7 @@ def expand_list(flat_list): mixed_list.append(result) return mixed_list + def add_icon_to_cells(data, icon_indices, icon="🔒"): """ Adds an icon to specified cells in the data. @@ -56,18 +89,20 @@ def add_icon_to_cells(data, icon_indices, icon="🔒"): - new_data: deep copy of data with icons added """ from copy import deepcopy + new_data = deepcopy(data) for row_idx, cols in enumerate(icon_indices): for col_idx in cols: - cell = new_data[row_idx][col_idx-1] + cell = new_data[row_idx][col_idx - 1] if isinstance(cell, str): - new_data[row_idx][col_idx-1] = f"{cell}{icon}" + new_data[row_idx][col_idx - 1] = f"{cell}{icon}" elif isinstance(cell, list): cell[-1] += icon - new_data[row_idx][col_idx-1] = cell + new_data[row_idx][col_idx - 1] = cell return new_data + def remove_icon_from_cells(data, icon="🔒"): """ Removes the icon from all cells that start with it. @@ -80,18 +115,20 @@ def remove_icon_from_cells(data, icon="🔒"): - new_data: deep copy of data with icons removed """ from copy import deepcopy + new_data = deepcopy(data) for i, row in enumerate(new_data): for j, cell in enumerate(row): if isinstance(cell, str): - if cell.endswith(f"{icon}"): # cells can also be list in case of multiple selection - new_data[i][j] = cell[:-(len(icon))] + if cell.endswith(f"{icon}"): # cells can also be list in case of multiple selection + new_data[i][j] = cell[: -(len(icon))] if isinstance(cell, list): if cell[-1].endswith(icon): - cell[-1] = cell[-1][:-(len(icon))] + cell[-1] = cell[-1][: -(len(icon))] return new_data + def add_table_to_tab(tab, table_data): for child in tab.winfo_children(): child.destroy() @@ -114,7 +151,7 @@ def __init__(self, parent, headers, types, read_only_data): print(read_only_data) self.types = ["checkbox"] + types self.read_only_data = [set(r) for r in read_only_data] - #style.configure("Treeview", font=theme.default_font) + # style.configure("Treeview", font=theme.default_font) self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse") for i, header in enumerate(self.headers): self.tree.heading(header, text=header) @@ -149,7 +186,6 @@ def toggle_row(self, row_id, item_index): self.tree.set(row_id, 0, "✅") def get_modified_data(self): - return [row[1:] for row in self.rows_data] # exclude checkbox column def edit_cell(self, event): @@ -198,7 +234,6 @@ def apply_to_selected(new_value): entry.place(x=x, y=y, width=width, height=height) entry.focus_set() - def on_return(event): new_value = entry.get() apply_to_selected(new_value) @@ -209,7 +244,9 @@ def on_return(event): elif type_ == "combo": options = self.multi_select_options.get(self.headers[col], []) - combo = ttk.Combobox(self.tree, values=options, state="readonly", style="PyAEDT.TCombobox", font=theme.default_font) + combo = ttk.Combobox( + self.tree, values=options, state="readonly", style="PyAEDT.TCombobox", font=theme.default_font + ) combo.place(x=x, y=y, width=width, height=height) combo.set(value) @@ -250,7 +287,6 @@ def confirm(): self.wait_window(top) - class IcepakModelReviewer(ExtensionCommon): def __init__(self, withdraw: bool = False): # Initialize the common extension class with the title and theme color @@ -275,10 +311,12 @@ def add_extension_content(self): notebook.add(self.root.materials_tab, text="Material") self.root.models_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") notebook.add(self.root.models_tab, text="Models") - ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton").pack(side=tk.LEFT, - padx=5) + ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton").pack( + side=tk.LEFT, padx=5 + ) ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton").pack( - side=tk.LEFT, padx=5) + side=tk.LEFT, padx=5 + ) def load_project(self): print("Loading project...") @@ -294,9 +332,9 @@ def load_project(self): ipk = Icepak() data = export_config_file(ipk) print("config_file_exported") - #print(data) + # print(data) self.root.json_data = data - desktop.release_desktop(close_projects=False, close_on_exit= False) + desktop.release_desktop(close_projects=False, close_on_exit=False) # --- Tabbed Interface --- table_data = extract_boundary_data(data) self.root.bc_table = add_table_to_tab(self.root.boundary_tab, table_data) @@ -331,12 +369,11 @@ def update_project(self): combined_data = {**new_model_data, **new_mat_data, **new_bc_data} print(differences) import_config_file(ipk, combined_data) - desktop.release_desktop(False,False) - + desktop.release_desktop(False, False) # === Main Application === if __name__ == "__main__": - #main() + # main() extension = IcepakModelReviewer(withdraw=False) - tk.mainloop() \ No newline at end of file + tk.mainloop() diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py index e69de29bb2d1..b78d8fed76c9 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py index e0c1b25c8f10..4691d40e58c0 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py @@ -1,8 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import json import os - def export_config_file(aedtapp): aedtapp.configurations.options.export_monitor = False aedtapp.configurations.options.export_native_components = False @@ -12,14 +35,14 @@ def export_config_file(aedtapp): aedtapp.configurations.options.export_mesh_operations = False aedtapp.configurations.options.export_optimizations = False config_file = aedtapp.configurations.export_config() - with open(config_file, 'r') as file: + with open(config_file, "r") as file: data = json.load(file) return data def import_config_file(aedtapp, json_data): full_path = os.path.abspath("load.json") - with open(full_path, 'w') as file: + with open(full_path, "w") as file: json.dump(json_data, file) print(f"json file path is {full_path}") out = aedtapp.configurations.import_config(full_path) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py index 916eb7c7d5d5..d34cb2ba34dd 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py @@ -1,11 +1,36 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import copy + def extract_boundary_data(data): boundary_data = [] object_mapping = data.get("general", {}).get("object_mapping", {}) read_only_cols = [] selection_dict = {} - headings = ["Boundary Name", "Boundary Type", "Selected Objects", "BC Name 1", "Value 1","BC Name 2", "Value 2"] + headings = ["Boundary Name", "Boundary Type", "Selected Objects", "BC Name 1", "Value 1", "BC Name 2", "Value 2"] type_list = ["text", "text", "multiple_text", "text", "text", "text", "text"] # Convert mapping to ensure all values are names (some are lists) id_to_name = {} @@ -19,9 +44,9 @@ def extract_boundary_data(data): selection_dict["Selected Objects"] = all_objects for boundary_name, boundary_details in data.get("boundaries", {}).items(): - cols = [1,2,4,6] + cols = [1, 2, 4, 6] boundary_type = boundary_details.get("BoundType", "") - #block_type = boundary_details.get("Block Type", "") # Solid or Fluid + # block_type = boundary_details.get("Block Type", "") # Solid or Fluid if boundary_type == "Block": use_total_power = boundary_details.get("Use Total Power", "") use_external_conditions = boundary_details.get("Use External Conditions", "") @@ -32,8 +57,9 @@ def extract_boundary_data(data): value1 = boundary_details.get("Total Power", "0W") # Default to "0W" if missing object_ids = boundary_details.get("Objects", []) # Default to empty list if missing selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) cols.append(7) read_only_cols.append(cols) elif use_external_conditions: @@ -43,8 +69,9 @@ def extract_boundary_data(data): value2 = boundary_details.get("Temperature", "0cel") object_ids = boundary_details.get("Objects", []) # Default to empty list if missing selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) read_only_cols.append(cols) else: bc_name1 = "Power Density" @@ -53,8 +80,9 @@ def extract_boundary_data(data): value1 = boundary_details.get("Power Density", "0w_per_m3") object_ids = boundary_details.get("Objects", []) # Default to empty list if missing selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) cols.append(7) read_only_cols.append(cols) @@ -67,11 +95,12 @@ def extract_boundary_data(data): value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing print(f"Faces id {object_ids}") - #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] - #print(f"converted faces id {selected_objects}") + # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + # print(f"converted faces id {selected_objects}") selected_objects = [str(ids) for ids in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) cols.append(3) cols.append(7) read_only_cols.append(cols) @@ -81,10 +110,11 @@ def extract_boundary_data(data): value1 = boundary_details.get("Total Power", "0W") value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing - #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] selected_objects = [str(ids) for ids in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) cols.append(3) cols.append(7) read_only_cols.append(cols) @@ -94,15 +124,17 @@ def extract_boundary_data(data): value1 = boundary_details.get("Temperature", "0cel") value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing - #selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] + # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] selected_objects = [str(ids) for ids in object_ids] - boundary_data.append([boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2]) + boundary_data.append( + [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] + ) cols.append(3) cols.append(7) read_only_cols.append(cols) return headings, type_list, selection_dict, boundary_data, read_only_cols + def extract_model_data(data): object_data = [] bulk_materials = set() @@ -130,7 +162,7 @@ def extract_model_data(data): else: modelling = "Non-Model" - if bulk_material == '""' or bulk_material == '': + if bulk_material == '""' or bulk_material == "": bulk_material = "Not Specified" bulk_materials.add(bulk_material) else: @@ -141,7 +173,7 @@ def extract_model_data(data): data["objects"][obj_name]["SurfaceMaterial"] = surface_material surface_material = "Not Specified" surface_materials.add(surface_material) - elif surface_material == '': + elif surface_material == "": surface_material = "Not Specified" surface_materials.add(surface_material) elif surface_material == None: @@ -149,21 +181,30 @@ def extract_model_data(data): surface_materials.add(surface_material) else: surface_material = surface_material.strip('"') - data["objects"][obj_name]["SurfaceMaterial"] = surface_material #removing "" in the source + data["objects"][obj_name]["SurfaceMaterial"] = surface_material # removing "" in the source surface_materials.add(surface_material) - object_data.append([ component_name, bulk_material, surface_material, solve_inside, modelling]) + object_data.append([component_name, bulk_material, surface_material, solve_inside, modelling]) read_only_cols.append(cols) selection_dict["Bulk Material"] = list(bulk_materials) selection_dict["Surface Material"] = list(surface_materials) return headings, type_list, selection_dict, object_data, read_only_cols + def extract_material_data(data): materials = data.get("materials", {}) extracted_data = [] read_only_cols = [] - headings = ["Material Name", "Material Type", "Thermal Conductivity", "Mass Density", "Specific Heat", - "Thermal Expansion Coefficient", "Diffusivity", "Viscosity"] + headings = [ + "Material Name", + "Material Type", + "Thermal Conductivity", + "Mass Density", + "Specific Heat", + "Thermal Expansion Coefficient", + "Diffusivity", + "Viscosity", + ] type_list = ["text", "text", "text", "text", "text", "text", "text", "text"] selection_dict = {} @@ -177,7 +218,7 @@ def extract_material_data(data): thermal_conductivity = mat_details.get("thermal_conductivity", "N/A") # Handle anisotropic thermal conductivity case if isinstance(thermal_conductivity, dict): - thermal_conductivity = thermal_conductivity['property_type'] + thermal_conductivity = thermal_conductivity["property_type"] cols.append(3) mass_density = mat_details.get("mass_density", "N/A") specific_heat = mat_details.get("specific_heat", "N/A") @@ -186,32 +227,39 @@ def extract_material_data(data): diffusivity = mat_details.get("diffusivity", "N/A") viscosity = mat_details.get("viscosity", "N/A") - extracted_data.append([mat_name, material_type, thermal_conductivity, mass_density, specific_heat, - thermal_expansion_coefficient, diffusivity, viscosity - ]) + extracted_data.append( + [ + mat_name, + material_type, + thermal_conductivity, + mass_density, + specific_heat, + thermal_expansion_coefficient, + diffusivity, + viscosity, + ] + ) read_only_cols.append(cols) return headings, type_list, selection_dict, extracted_data, read_only_cols + def compare_and_update_boundary_data(original_data, modified_object_data, object_mapping): """ Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + # updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original differences = [] inverse_mapping = {str(v): k for k, v in object_mapping.items()} - updated_data = {"boundaries": {}, "general": {}} updated_data["general"]["object_mapping"] = {**original_data["general"]["object_mapping"], **inverse_mapping} modified_boundary = set() for row in modified_object_data: - (boundary_name, boundary_type, selected_objects, - bc_name1, value1, bc_name2, value2) = row + (boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2) = row original_obj = original_data["boundaries"][boundary_name] - updated_data["boundaries"][boundary_name]=copy.deepcopy(original_data["boundaries"][boundary_name]) - + updated_data["boundaries"][boundary_name] = copy.deepcopy(original_data["boundaries"][boundary_name]) # Convert string values back to boolean where necessary print("printing selected objects") @@ -223,29 +271,32 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object selected_object_ids = [int(i) if str(i).isdigit() else object_mapping[i] for i in selected_objects] selected_objects_list = [i for i in selected_objects] if isinstance(selected_objects, str): - selected_object_ids = [int(i.strip()) if str(i.strip()).isdigit() else object_mapping[i.strip()] - for i in selected_objects.split(",")] + selected_object_ids = [ + int(i.strip()) if str(i.strip()).isdigit() else object_mapping[i.strip()] + for i in selected_objects.split(",") + ] selected_objects_list = [i.strip() for i in selected_objects.split(",")] original_obj_ids = original_obj.get("Objects", []) if original_obj_ids: if set(original_obj_ids) != set(selected_object_ids): - differences.append( - f"{boundary_name}: {bc_name1} selected objects changed to '{selected_objects}'") - #updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids + differences.append(f"{boundary_name}: {bc_name1} selected objects changed to '{selected_objects}'") + # updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids updated_data["boundaries"][boundary_name]["Objects"] = selected_objects_list modified_boundary.add(boundary_name) if original_obj.get(bc_name1, "") != value1: differences.append( - f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'") + f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'" + ) updated_data["boundaries"][boundary_name][bc_name1] = value1 modified_boundary.add(boundary_name) if bc_name2 != "N/A": if original_obj.get(bc_name2, "") != value2: differences.append( - f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'") + f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'" + ) updated_data["boundaries"][boundary_name][bc_name2] = value2 modified_boundary.add(boundary_name) @@ -256,12 +307,13 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object return differences, modified_data + def compare_and_update_model_data(original_data, modified_object_data): """ Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + # updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original updated_data = {"objects": {}} differences = [] modified_objects = set() @@ -270,7 +322,7 @@ def compare_and_update_model_data(original_data, modified_object_data): obj_name, bulk_material, surface_material, solve_inside, modelling = row original_obj = original_data["objects"][obj_name] - updated_data["objects"][obj_name]=copy.deepcopy(original_data["objects"][obj_name]) + updated_data["objects"][obj_name] = copy.deepcopy(original_data["objects"][obj_name]) # Convert string values back to boolean where necessary solve_inside_bool = solve_inside == "True" @@ -280,25 +332,30 @@ def compare_and_update_model_data(original_data, modified_object_data): if not bulk_material == "Not Specified": if original_obj.get("Material", "") != bulk_material: differences.append( - f"{obj_name}: Bulk Material changed from '{original_obj.get('Material', '')}' to '{bulk_material}'") + f"{obj_name}: Bulk Material changed from '{original_obj.get('Material', '')}' to '{bulk_material}'" + ) updated_data["objects"][obj_name]["Material"] = bulk_material modified_objects.add(obj_name) if not surface_material == "Not Specified": - if original_obj.get("SurfaceMaterial", "")!= surface_material: + if original_obj.get("SurfaceMaterial", "") != surface_material: differences.append( - f"{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to '{surface_material}'") + f"{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to '{surface_material}'" + ) updated_data["objects"][obj_name]["SurfaceMaterial"] = surface_material modified_objects.add(obj_name) if original_obj.get("SolveInside", "") != solve_inside_bool: differences.append( - f"{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' to '{solve_inside_bool}'") + f"{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' to '{solve_inside_bool}'" + ) updated_data["objects"][obj_name]["SolveInside"] = solve_inside_bool modified_objects.add(obj_name) if original_obj.get("Model", "") != modelling_bool: - differences.append(f"{obj_name}: Modeling changed from '{original_obj.get('Model', '')}' to '{modelling_bool}'") + differences.append( + f"{obj_name}: Modeling changed from '{original_obj.get('Model', '')}' to '{modelling_bool}'" + ) updated_data["objects"][obj_name]["Model"] = modelling_bool updated_data["objects"][obj_name]["SurfaceMaterial"] = None modified_objects.add(obj_name) @@ -309,58 +366,74 @@ def compare_and_update_model_data(original_data, modified_object_data): return differences, modified_data + def compare_and_update_material_data(original_data, modified_object_data): """ Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - #updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + # updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original differences = [] updated_data = {"materials": {}} # Convert object data into a lookup dictionary for easy comparison modified_materials = set() for row in modified_object_data: - (mat_name, material_type, thermal_conductivity, - mass_density, specific_heat,thermal_expansion_coefficient, diffusivity, viscosity)= row + ( + mat_name, + material_type, + thermal_conductivity, + mass_density, + specific_heat, + thermal_expansion_coefficient, + diffusivity, + viscosity, + ) = row original_obj = original_data["materials"][mat_name] - updated_data["materials"][mat_name]=copy.deepcopy(original_data["materials"][mat_name]) + updated_data["materials"][mat_name] = copy.deepcopy(original_data["materials"][mat_name]) # Check for differences and update if not isinstance(original_obj.get("thermal_conductivity"), dict): if original_obj.get("thermal_conductivity", "") != thermal_conductivity: differences.append( - f"{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' to '{thermal_conductivity}'") - updated_data["materials"][mat_name]["thermal_conductivity"]= thermal_conductivity + f"{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' to '{thermal_conductivity}'" + ) + updated_data["materials"][mat_name]["thermal_conductivity"] = thermal_conductivity modified_materials.add(mat_name) if original_obj.get("mass_density", "") != mass_density: differences.append( - f"{mat_name}: Mass density changed from '{original_obj.get('mass_density', '')}' to '{mass_density}'") + f"{mat_name}: Mass density changed from '{original_obj.get('mass_density', '')}' to '{mass_density}'" + ) updated_data["materials"][mat_name]["mass_density"] = mass_density modified_materials.add(mat_name) if original_obj.get("specific_heat", "") != specific_heat: differences.append( - f"{mat_name}: specific heat changed from '{original_obj.get('specific_heat', '')}' to '{specific_heat}'") + f"{mat_name}: specific heat changed from '{original_obj.get('specific_heat', '')}' to '{specific_heat}'" + ) updated_data["materials"][mat_name]["specific_heat"] = specific_heat modified_materials.add(mat_name) if original_obj.get("thermal_expansion_coefficient", "") != thermal_expansion_coefficient: - differences.append(f"{mat_name}: Thermal expansion coefficient changed " - f"from '{original_obj.get('thermal_expansion_coefficient', '')}' to '{thermal_expansion_coefficient}'") + differences.append( + f"{mat_name}: Thermal expansion coefficient changed " + f"from '{original_obj.get('thermal_expansion_coefficient', '')}' to '{thermal_expansion_coefficient}'" + ) updated_data["materials"][mat_name]["thermal_expansion_coefficient"] = thermal_expansion_coefficient modified_materials.add(mat_name) if original_obj.get("diffusivity", "") != diffusivity: - differences.append(f"{mat_name}: diffusivity changed " - f"from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'") + differences.append( + f"{mat_name}: diffusivity changed from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'" + ) updated_data["materials"][mat_name]["diffusivity"] = diffusivity modified_materials.add(mat_name) if original_obj.get("viscosity", "") != viscosity: - differences.append(f"{mat_name}: diffusivity changed " - f"from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'") + differences.append( + f"{mat_name}: diffusivity changed from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'" + ) updated_data["materials"][mat_name]["viscosity"] = diffusivity modified_materials.add(mat_name) @@ -369,10 +442,11 @@ def compare_and_update_material_data(original_data, modified_object_data): modified_data["materials"][mat_name] = copy.deepcopy(updated_data["materials"][mat_name]) return differences, modified_data + if __name__ == "__main__": import json sample_json = "test1.json" - with open(sample_json, 'r') as file: + with open(sample_json, "r") as file: data = json.load(file) - extract_boundary_data(data) \ No newline at end of file + extract_boundary_data(data) From fc1e25d559fbddf8a20392904401f3f87f456a6e Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Wed, 6 Aug 2025 08:26:21 +0000 Subject: [PATCH 04/50] chore: adding changelog file 6495.added.md [dependabot-skip] --- doc/changelog.d/6495.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/6495.added.md diff --git a/doc/changelog.d/6495.added.md b/doc/changelog.d/6495.added.md new file mode 100644 index 000000000000..ad021c6047ec --- /dev/null +++ b/doc/changelog.d/6495.added.md @@ -0,0 +1 @@ +Icepak model reviewer extension \ No newline at end of file From 72fe1c3b550901a1db91f9f4feb3c1cf3bc4abb4 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Tue, 12 Aug 2025 16:54:16 +0200 Subject: [PATCH 05/50] refactor and unit test cases for the toolkit --- .../icepak/icepak_model_reviewer.py | 55 ++++-- .../__init__.py | 0 .../backend.py | 4 - .../configuration_data_processing.py | 0 .../general/test_01_configuration_files.py | 156 +++++++++++++++++- .../extensions/test_icepak_model_reviewer.py | 67 ++++++++ 6 files changed, 260 insertions(+), 22 deletions(-) rename src/ansys/aedt/core/extensions/icepak/{icepak_model_reviewer => model_reviewer}/__init__.py (100%) rename src/ansys/aedt/core/extensions/icepak/{icepak_model_reviewer => model_reviewer}/backend.py (99%) rename src/ansys/aedt/core/extensions/icepak/{icepak_model_reviewer => model_reviewer}/configuration_data_processing.py (100%) create mode 100644 tests/unit/extensions/test_icepak_model_reviewer.py diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 3b7cc5422e4c..03372d5f60ca 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -1,6 +1,7 @@ import tkinter as tk from tkinter import ttk -from icepak_model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file +#from model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file from ansys.aedt.core.extensions.misc import get_aedt_version from ansys.aedt.core.extensions.misc import get_port from ansys.aedt.core.extensions.misc import get_process_id @@ -9,9 +10,12 @@ from ansys.aedt.core.extensions.misc import ExtensionCommonData from ansys.aedt.core.extensions.misc import ExtensionTheme from ansys.aedt.core import * +from ansys.aedt.core.internal.errors import AEDTRuntimeError -from icepak_model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data +#from model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ +# compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data port = get_port() version = get_aedt_version() @@ -110,8 +114,6 @@ class Table(tk.Frame): def __init__(self, parent, headers, types, read_only_data): super().__init__(parent) self.headers = ["✔"] + headers - print("read only data") - print(read_only_data) self.types = ["checkbox"] + types self.read_only_data = [set(r) for r in read_only_data] #style.configure("Treeview", font=theme.default_font) @@ -275,14 +277,17 @@ def add_extension_content(self): notebook.add(self.root.materials_tab, text="Material") self.root.models_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") notebook.add(self.root.models_tab, text="Models") - ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton").pack(side=tk.LEFT, - padx=5) - ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton").pack( - side=tk.LEFT, padx=5) + self.load_button = ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton") + self.load_button.pack(side=tk.LEFT,padx=5) + self.update_button = ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton") + self.update_button.pack(side=tk.LEFT, padx=5) - def load_project(self): - print("Loading project...") + def check_design_type(self): + """Check if the active design is an Icepak design.""" + if self.aedt_application.design_type != "Icepak": + raise AEDTRuntimeError("This extension can only be used with Icepak designs.") + def get_project_data(self): desktop = Desktop( new_desktop=False, version=version, @@ -290,13 +295,29 @@ def load_project(self): aedt_process_id=aedt_process_id, student_version=is_student(), ) - ipk = Icepak() data = export_config_file(ipk) + desktop.release_desktop(close_projects=False, close_on_exit=False) + return data + + def import_data_to_project(self, combined_data): + desktop = Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student(), + ) + ipk = Icepak() + import_config_file(ipk, combined_data) + desktop.release_desktop(False, False) + + def load_project(self): + print("Loading project...") print("config_file_exported") - #print(data) + data = self.get_project_data() self.root.json_data = data - desktop.release_desktop(close_projects=False, close_on_exit= False) + # --- Tabbed Interface --- table_data = extract_boundary_data(data) self.root.bc_table = add_table_to_tab(self.root.boundary_tab, table_data) @@ -317,6 +338,8 @@ def update_project(self): ipk = Icepak() obj_mapping = get_object_id_mapping(ipk) + desktop.release_desktop(False,False) + bc_data = self.root.bc_table.get_modified_data() bc_data = expand_list(remove_icon_from_cells(bc_data)) differences, new_bc_data = compare_and_update_boundary_data(self.root.json_data, bc_data, obj_mapping) @@ -328,10 +351,10 @@ def update_project(self): model_data = self.root.model_table.get_modified_data() model_data = expand_list(remove_icon_from_cells(model_data)) differences, new_model_data = compare_and_update_model_data(self.root.json_data, model_data) - combined_data = {**new_model_data, **new_mat_data, **new_bc_data} print(differences) - import_config_file(ipk, combined_data) - desktop.release_desktop(False,False) + combined_data = {**new_model_data, **new_mat_data, **new_bc_data} + self.import_data_to_project(combined_data) + diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py similarity index 100% rename from src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/__init__.py rename to src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py similarity index 99% rename from src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py rename to src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index e0c1b25c8f10..a1bd680f410f 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -1,8 +1,6 @@ import json import os - - def export_config_file(aedtapp): aedtapp.configurations.options.export_monitor = False aedtapp.configurations.options.export_native_components = False @@ -16,7 +14,6 @@ def export_config_file(aedtapp): data = json.load(file) return data - def import_config_file(aedtapp, json_data): full_path = os.path.abspath("load.json") with open(full_path, 'w') as file: @@ -30,7 +27,6 @@ def import_config_file(aedtapp, json_data): print("import has issues") return None - def get_object_id_mapping(aedtapp): object_id_map = {name: aedtapp.modeler.get_obj_id(name) for name in aedtapp.modeler.object_names} return object_id_map diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py similarity index 100% rename from src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer/configuration_data_processing.py rename to src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index 10afac99ebf6..871b4015019e 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -26,12 +26,12 @@ import os import time -import pytest - from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d +import pytest + from tests import TESTS_GENERAL_PATH from tests.system.general.conftest import config @@ -76,6 +76,18 @@ def q2dtest(add_app): return app +@pytest.fixture(scope="class") +def icepak_a(add_app): + app = add_app(project_name=ipk_name + "_a", application=Icepak) + return app + + +@pytest.fixture(scope="class") +def icepak_b(add_app): + app = add_app(project_name=ipk_name + "_b", application=Icepak) + return app + + @pytest.fixture(scope="class") def hfss3dl_a(add_app): app = add_app(project_name=diff_proj_name, application=Hfss3dLayout, subfolder=test_subfolder) @@ -174,6 +186,146 @@ def test_03_q2d_export(self, q2dtest, add_app): assert q2dtest.configurations.options.import_parametrics app.close_project(save=False) + def test_04a_icepak(self, icepak_a, aedtapp, add_app): + box1 = icepak_a.modeler.create_box([0, 0, 0], [10, 10, 10]) + icepak_a.monitor.assign_point_monitor_to_vertex(box1.vertices[0].id) + box1.surface_material_name = "Shellac-Dull-surface" + region = icepak_a.modeler["Region"] + icepak_a.monitor.assign_point_monitor_in_object(box1.name) + icepak_a.monitor.assign_face_monitor(box1.faces[0].id) + icepak_a.monitor.assign_point_monitor([5, 5, 5]) + icepak_a.assign_openings(air_faces=region.bottom_face_x.id) + icepak_a.create_setup() + icepak_a.modeler.create_coordinate_system([10, 1, 10]) + icepak_a.mesh.assign_mesh_region([box1.name]) + icepak_a.mesh.global_mesh_region.MaxElementSizeX = "2mm" + icepak_a.mesh.global_mesh_region.MaxElementSizeY = "3mm" + icepak_a.mesh.global_mesh_region.MaxElementSizeZ = "4mm" + icepak_a.mesh.global_mesh_region.MaxSizeRatio = 2 + icepak_a.mesh.global_mesh_region.UserSpecifiedSettings = True + icepak_a.mesh.global_mesh_region.UniformMeshParametersType = "XYZ Max Sizes" + icepak_a.mesh.global_mesh_region.MaxLevels = 2 + icepak_a.mesh.global_mesh_region.BufferLayers = 1 + icepak_a.mesh.global_mesh_region.update() + cs = aedtapp.modeler.create_coordinate_system(name="useless") + cs.props["OriginX"] = 20 + cs.props["OriginY"] = 20 + cs.props["OriginZ"] = 20 + icepak_a.create_dataset( + "test_dataset", + [1, 2, 3, 4], + [1, 2, 3, 4], + z=None, + v=None, + is_project_dataset=False, + x_unit="cel", + y_unit="W", + v_unit="", + ) + filename = icepak_a.design_name + icepak_a.export_3d_model(filename, icepak_a.working_directory, ".x_b", [], []) + assert icepak_a.configurations.options.export_monitor + assert icepak_a.configurations.options.export_native_components + assert icepak_a.configurations.options.export_datasets + conf_file = icepak_a.configurations.export_config() + assert icepak_a.configurations.validate(conf_file) + f = icepak_a.create_fan("test_fan") + idx = 0 + icepak_a.monitor.assign_point_monitor_to_vertex( + list(icepak_a.modeler.user_defined_components[f.name].parts.values())[idx].vertices[0].id + ) + assert icepak_a.configurations.export_config() + f.delete() + file_path = os.path.join(icepak_a.working_directory, filename + ".x_b") + app = add_app(application=Icepak, project_name="new_proj_Ipk_a", just_open=True) + app.modeler.import_3d_cad(file_path) + out = app.configurations.import_config(conf_file) + assert isinstance(out, dict) + assert app.configurations.validate(out) + assert app.configurations.results.global_import_success + # backward compatibility + with open(conf_file, "r") as f: + old_dict_format = json.load(f) + old_dict_format["monitor"] = old_dict_format.pop("monitors") + old_mon_dict = {} + for mon in old_dict_format["monitor"]: + old_mon_dict[mon["Name"]] = mon + old_mon_dict[mon["Name"]].pop("Name") + old_dict_format["monitor"] = old_mon_dict + old_dataset_dict = {} + for dat in old_dict_format["datasets"]: + old_dataset_dict[dat["Name"]] = dat + old_dataset_dict[dat["Name"]].pop("Name") + old_dict_format["datasets"] = old_dataset_dict + old_conf_file = conf_file + ".old.json" + with open(old_conf_file, "w") as f: + json.dump(old_dict_format, f) + app = add_app(application=Icepak, project_name="new_proj_Ipk_a_test2", just_open=True) + app.modeler.import_3d_cad(file_path) + out = app.configurations.import_config(old_conf_file) + assert isinstance(out, dict) + assert app.configurations.results.global_import_success + app.close_project(save=False) + + @pytest.mark.skipif( + config["desktopVersion"] < "2023.1" and config["use_grpc"], + reason="Not working in 2022.2 gRPC", + ) + def test_04b_icepak(self, icepak_b, add_app): + box1 = icepak_b.modeler.create_box([0, 0, 0], [10, 10, 10]) + box1.surface_material_name = "Shellac-Dull-surface" + region = icepak_b.modeler["Region"] + icepak_b.monitor.assign_point_monitor_in_object(box1.name) + icepak_b.monitor.assign_face_monitor(box1.faces[0].id) + icepak_b.monitor.assign_point_monitor([5, 5, 5]) + icepak_b.assign_openings(air_faces=region.bottom_face_x.id) + icepak_b.create_setup() + icepak_b.modeler.create_coordinate_system([10, 1, 10]) + icepak_b.mesh.assign_mesh_region([box1.name]) + icepak_b.mesh.global_mesh_region.MaxElementSizeX = "2mm" + icepak_b.mesh.global_mesh_region.MaxElementSizeY = "3mm" + icepak_b.mesh.global_mesh_region.MaxElementSizeZ = "4mm" + icepak_b.mesh.global_mesh_region.MaxSizeRatio = 2 + icepak_b.mesh.global_mesh_region.UserSpecifiedSettings = True + icepak_b.mesh.global_mesh_region.UniformMeshParametersType = "XYZ Max Sizes" + icepak_b.mesh.global_mesh_region.MaxLevels = 2 + icepak_b.mesh.global_mesh_region.BufferLayers = 1 + icepak_b.mesh.global_mesh_region.update() + cs = icepak_b.modeler.create_coordinate_system(name="useless") + cs.props["OriginX"] = 20 + cs.props["OriginY"] = 20 + cs.props["OriginZ"] = 20 + icepak_b.create_dataset( + "test_dataset", + [1, 2, 3, 4], + [1, 2, 3, 4], + z=None, + v=None, + is_project_dataset=False, + x_unit="cel", + y_unit="W", + v_unit="", + ) + filename = icepak_b.design_name + icepak_b.export_3d_model(filename, icepak_b.working_directory, ".x_b", [], []) + fan = icepak_b.create_fan("test_fan") + icepak_b.modeler.user_defined_components[fan.name].move([1, 2, 3]) + fan2 = icepak_b.modeler.user_defined_components[fan.name].duplicate_along_line([4, 5, 6]) + icepak_b.modeler.user_defined_components[fan.name].rotate("Y") + fan3 = icepak_b.modeler.user_defined_components[fan.name].duplicate_around_axis("Z") + icepak_b.modeler.user_defined_components[fan.name].move([1, 2, 3]) + fan4 = icepak_b.modeler.user_defined_components[fan.name].duplicate_around_axis("Z") + icepak_b.modeler.user_defined_components[fan2[0]].duplicate_and_mirror([4, 5, 6], [1, 2, 3]) + conf_file = icepak_b.configurations.export_config() + assert icepak_b.configurations.validate(conf_file) + file_path = os.path.join(icepak_b.working_directory, filename + ".x_b") + app = add_app(application=Icepak, project_name="new_proj_Ipk", just_open=True) + app.modeler.import_3d_cad(file_path) + out = app.configurations.import_config(conf_file) + assert isinstance(out, dict) + assert app.configurations.validate(out) + assert app.configurations.results.global_import_success + def test_05a_hfss3dlayout_setup(self, hfss3dl_a, local_scratch): setup2 = hfss3dl_a.create_setup("My_HFSS_Setup_2") # Insert a setup. assert setup2.props["ViaNumSides"] == 6 # Check the default value. diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py new file mode 100644 index 000000000000..2f33454b3760 --- /dev/null +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -0,0 +1,67 @@ +from textwrap import dedent +from tkinter import TclError +from unittest.mock import patch + +import pytest + +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer + + +import pytest +from unittest.mock import patch +import json +from tests import TESTS_UNIT_PATH +import os + +def load_json(): + + json_file = os.path.join(TESTS_UNIT_PATH, 'extensions','graphics_card.json') + with open(json_file, 'r') as file: + data = json.load(file) + return data + +@pytest.fixture +def patched_loader(): + with patch.object(IcepakModelReviewer, "get_project_data", side_effect=load_json) as mock_loader: + yield mock_loader + +def test_icepak_model_reviewer(mock_icepak_app): + """Test instantiation of the IcepakModelReviewer.""" + extension = IcepakModelReviewer(withdraw=True) + + assert EXTENSION_TITLE == extension.root.title() + assert "light" == extension.root.theme + + extension.root.destroy() + +def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + boundary_table = extension.root.boundary_tab.winfo_children()[0] + assert boundary_table.tree is not None + assert len(boundary_table.tree.get_children()) == 3 + +def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + boundary_table = extension.root.boundary_tab.winfo_children()[0] + row1 = boundary_table.tree.get_children()[0] + row2 = boundary_table.tree.get_children()[1] + row3 = boundary_table.tree.get_children()[2] + assert boundary_table.tree.item(row1)['values'][5] == '4W' + assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' + assert boundary_table.tree.item(row3)['values'][5] == '1W' + +def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loader): + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + boundary_table = extension.root.boundary_tab.winfo_children()[0] + row1 = boundary_table.tree.get_children()[0] + row2 = boundary_table.tree.get_children()[1] + row3 = boundary_table.tree.get_children()[2] + boundary_table.tree.set(row1)['values'][5] ='2W' + boundary_table.tree.set(row2)['values'][5] ='2w_per_m3' + boundary_table.tree.set(row3)['values'][5] ='1.5W' + extension.update_button.invoke() + From c4efca434db1c686e989545f9acd5e0a29cf55b7 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Wed, 3 Sep 2025 16:54:00 +0200 Subject: [PATCH 06/50] system test case for the toolkit --- .../icepak/icepak_model_reviewer.py | 43 +- .../extensions/icepak/toolkits_catalog.toml | 6 + .../example_models/T45/Graphics_Card.aedt | 3098 +++++++++++++++++ .../extensions/test_icepak_model_reviewer.py | 54 +- 4 files changed, 3175 insertions(+), 26 deletions(-) create mode 100644 tests/system/extensions/example_models/T45/Graphics_Card.aedt diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 03372d5f60ca..474228a00903 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -1,4 +1,5 @@ import tkinter as tk +import os from tkinter import ttk from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file #from model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file @@ -151,8 +152,8 @@ def toggle_row(self, row_id, item_index): self.tree.set(row_id, 0, "✅") def get_modified_data(self): - - return [row[1:] for row in self.rows_data] # exclude checkbox column + return [self.tree.item(row)["values"][1: ] for row in self.tree.get_children()] + #return [row[1:] for row in self.rows_data] # exclude checkbox column def edit_cell(self, event): region = self.tree.identify("region", event.x, event.y) @@ -263,6 +264,7 @@ def __init__(self, withdraw: bool = False): add_custom_content=False, ) + self.combined_data = None self.add_extension_content() def add_extension_content(self): @@ -297,7 +299,8 @@ def get_project_data(self): ) ipk = Icepak() data = export_config_file(ipk) - desktop.release_desktop(close_projects=False, close_on_exit=False) + if "PYTEST_CURRENT_TEST" not in os.environ: + desktop.release_desktop(close_projects=False, close_on_exit=False) return data def import_data_to_project(self, combined_data): @@ -310,7 +313,22 @@ def import_data_to_project(self, combined_data): ) ipk = Icepak() import_config_file(ipk, combined_data) - desktop.release_desktop(False, False) + if "PYTEST_CURRENT_TEST" not in os.environ: + desktop.release_desktop(False, False) + + def object_id_mapping(self): + desktop = Desktop( + new_desktop=False, + version=version, + port=port, + aedt_process_id=aedt_process_id, + student_version=is_student(), + ) + ipk = Icepak() + mapping = get_object_id_mapping(ipk) + if "PYTEST_CURRENT_TEST" not in os.environ: + desktop.release_desktop(False, False) + return mapping def load_project(self): print("Loading project...") @@ -328,18 +346,7 @@ def load_project(self): def update_project(self): print("Updating project...") - desktop = Desktop( - new_desktop=False, - version=version, - port=port, - aedt_process_id=aedt_process_id, - student_version=is_student(), - ) - - ipk = Icepak() - obj_mapping = get_object_id_mapping(ipk) - desktop.release_desktop(False,False) - + obj_mapping = self.object_id_mapping() bc_data = self.root.bc_table.get_modified_data() bc_data = expand_list(remove_icon_from_cells(bc_data)) differences, new_bc_data = compare_and_update_boundary_data(self.root.json_data, bc_data, obj_mapping) @@ -352,8 +359,8 @@ def update_project(self): model_data = expand_list(remove_icon_from_cells(model_data)) differences, new_model_data = compare_and_update_model_data(self.root.json_data, model_data) print(differences) - combined_data = {**new_model_data, **new_mat_data, **new_bc_data} - self.import_data_to_project(combined_data) + self.combined_data = {**new_model_data, **new_mat_data, **new_bc_data} + self.import_data_to_project(self.combined_data) diff --git a/src/ansys/aedt/core/extensions/icepak/toolkits_catalog.toml b/src/ansys/aedt/core/extensions/icepak/toolkits_catalog.toml index cfa37bd6a686..4eb4b74e94fb 100644 --- a/src/ansys/aedt/core/extensions/icepak/toolkits_catalog.toml +++ b/src/ansys/aedt/core/extensions/icepak/toolkits_catalog.toml @@ -2,4 +2,10 @@ name = "Create Power Map from CSV file" script = "power_map_from_csv.py" icon = "images/large/power_map.png" +template = "run_pyaedt_toolkit_script" + +[IcepakModelReviewer] +name = "Icepak Model Reviewer" +script = "icepak_model_reviewer.py" +icon = "images/large/push.png" template = "run_pyaedt_toolkit_script" \ No newline at end of file diff --git a/tests/system/extensions/example_models/T45/Graphics_Card.aedt b/tests/system/extensions/example_models/T45/Graphics_Card.aedt new file mode 100644 index 000000000000..daec8388b4c7 --- /dev/null +++ b/tests/system/extensions/example_models/T45/Graphics_Card.aedt @@ -0,0 +1,3098 @@ +$begin 'AnsoftProject' + Created='Thu Mar 02 13:18:51 2017' + Product='ElectronicsDesktop' + FileOwnedByWorkbench=false + $begin 'Desktop' + Version(2025, 1) + InfrastructureVersion(1, 0) + $begin 'FactoryHeader' + $begin 'geometry3deditor' + KernelVersion(2, 0) + ProjectContainsGeometry3D='1' + $end 'geometry3deditor' + $end 'FactoryHeader' + $end 'Desktop' + UsesAdvancedFeatures=false + NextUniqueID=0 + MoveBackwards=false + $begin 'HFSSEnvironment' + Version(1, 0) + $end 'HFSSEnvironment' + $begin 'PlanarEMEnvironment' + Version(1, 0) + $end 'PlanarEMEnvironment' + $begin 'Q3DEnvironment' + Version(1, 0) + $end 'Q3DEnvironment' + $begin '2DExtractorEnvironment' + Version(1, 0) + $end '2DExtractorEnvironment' + $begin 'NexximEnvironment' + Version(1, 0) + $end 'NexximEnvironment' + $begin 'NexximNetlistEnvironment' + Version(1, 0) + $end 'NexximNetlistEnvironment' + $begin 'EmitEnvironment' + Version(1, 0) + $end 'EmitEnvironment' + $begin 'Maxwell3DEnvironment' + Version(1, 0) + $end 'Maxwell3DEnvironment' + $begin 'Maxwell2DEnvironment' + Version(1, 0) + $end 'Maxwell2DEnvironment' + $begin 'RMxprtEnvironment' + Version(1, 0) + $end 'RMxprtEnvironment' + $begin 'MaxCirEnvironment' + Version(1, 0) + $end 'MaxCirEnvironment' + $begin 'SimplorerEnvironment' + Version(1, 0) + $end 'SimplorerEnvironment' + $begin 'IcepakEnvironment' + Version(1, 0) + $end 'IcepakEnvironment' + $begin 'MechanicalEnvironment' + Version(1, 0) + $end 'MechanicalEnvironment' + $begin 'SchematicEnvironment' + Version(1, 0) + $end 'SchematicEnvironment' + $begin 'geometry3deditor' + Version(1, 0) + $end 'geometry3deditor' + ReadVersion=12 + $begin 'DesignMgrEnvironment' + CompInstCounter=1 + GPortCounter=0 + NetCounter=0 + Alias('Ieee;Simplorer Elements\\Ieee', 'Std;Simplorer Elements\\Std', 'Basic_VHDLAMS;Simplorer Elements\\Basic Elements VHDLAMS\\Basic Elements VHDLAMS', 'Digital_Elements;Simplorer Elements\\Digital Elements\\Digital Elements', 'Transformations;Simplorer Elements\\Tools\\Transformations\\Transformations', 'HEV_VHDLAMS;Simplorer Elements\\HEV VHDLAMS\\HEV VHDLAMS', 'automotive_vda;Simplorer Elements\\VDALibs VHDLAMS\\automotive_vda', 'example_boardnet;Simplorer Elements\\VDALibs VHDLAMS\\example_boardnet', 'example_ecar;Simplorer Elements\\VDALibs VHDLAMS\\example_ecar', 'fundamentals_vda;Simplorer Elements\\VDALibs VHDLAMS\\fundamentals_vda', 'hybrid_emc_vda;Simplorer Elements\\VDALibs VHDLAMS\\hybrid_emc_vda', 'megma;Simplorer Elements\\VDALibs VHDLAMS\\megma', 'modelica_rotational;Simplorer Elements\\VDALibs VHDLAMS\\modelica_rotational', 'modelica_thermal;Simplorer Elements\\VDALibs VHDLAMS\\modelica_thermal', 'modelica_translational;Simplorer Elements\\VDALibs VHDLAMS\\modelica_translational', 'spice2vhd;Simplorer Elements\\VDALibs VHDLAMS\\spice2vhd', 'spice2vhd_devices;Simplorer Elements\\VDALibs VHDLAMS\\spice2vhd_devices', 'aircraft_electrical_vhdlams;Simplorer Elements\\Aircraft Electrical VHDLAMS\\Aircraft Electrical VHDLAMS', 'power_system_vhdlams;Simplorer Elements\\Power System VHDLAMS\\Power System VHDLAMS') + $end 'DesignMgrEnvironment' + $begin 'ProjectDatasets' + NextUniqueID=1 + MoveBackwards=false + DatasetType='ProjectDatasetType' + $begin 'DatasetDefinitions' + $begin '$Ceramic_material_39' + ID=0 + $begin 'Coordinates' + DimUnits[2: '', ''] + Points[8: -273.15, 0.067032967032967, -196.15, 0.067032967032967, 99.85, 1, 726.85, 1] + $end 'Coordinates' + $end '$Ceramic_material_39' + $end 'DatasetDefinitions' + $end 'ProjectDatasets' + VariableOrders[0:] + $begin 'Definitions' + $begin 'Materials' + $begin 'Al-Extruded' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + $begin 'AttachedData' + $begin 'MatAppearanceData' + property_data='appearance_data' + Red=232 + Green=235 + Blue=235 + $end 'MatAppearanceData' + $end 'AttachedData' + permittivity='1' + permeability='1' + conductivity='0' + dielectric_loss_tangent='0' + magnetic_loss_tangent='0' + thermal_conductivity='152' + mass_density='2000' + specific_heat='900' + youngs_modulus='0' + poissons_ratio='0' + thermal_expansion_coefficient='0' + $begin 'thermal_material_type' + property_type='ChoiceProperty' + Choice='Solid' + $end 'thermal_material_type' + diffusivity='0.8' + molecular_mass='0' + viscosity='0' + $begin 'clarity_type' + property_type='ChoiceProperty' + Choice='Opaque' + $end 'clarity_type' + ModTime=1753886315 + Library='' + LibLocation='Project' + ModSinceLib=true + $end 'Al-Extruded' + $begin 'air' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Electromagnetic', 'Thermal') + $end 'PhysicsTypes' + $begin 'AttachedData' + $begin 'MatAppearanceData' + property_data='appearance_data' + Red=230 + Green=230 + Blue=230 + Transparency=0.949999988079071 + $end 'MatAppearanceData' + $end 'AttachedData' + permittivity='1.0006' + permeability='1.0000004' + conductivity='0' + dielectric_loss_tangent='0' + magnetic_loss_tangent='0' + thermal_conductivity='0.0261' + mass_density='1.1614' + specific_heat='1005' + youngs_modulus='0' + poissons_ratio='0' + thermal_expansion_coefficient='0.00333' + $begin 'thermal_material_type' + property_type='ChoiceProperty' + Choice='Fluid' + $end 'thermal_material_type' + diffusivity='2.88e-05' + molecular_mass='0.028966' + viscosity='1.84e-05' + material_refractive_index='1.000293' + $begin 'clarity_type' + property_type='ChoiceProperty' + Choice='Transparent' + $end 'clarity_type' + ModTime=1753886316 + Library='' + LibLocation='Project' + ModSinceLib=true + $end 'air' + $begin 'PCB_Material' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + $begin 'AttachedData' + $begin 'MatAppearanceData' + property_data='appearance_data' + Red=210 + Green=105 + Blue=30 + Transparency=0 + $end 'MatAppearanceData' + $end 'AttachedData' + permittivity='1' + permeability='1' + conductivity='0' + dielectric_loss_tangent='0' + magnetic_loss_tangent='0' + thermal_conductivity='0.01' + mass_density='1' + specific_heat='2' + youngs_modulus='0' + poissons_ratio='0' + thermal_expansion_coefficient='1' + diffusivity='0.8' + molecular_mass='0' + viscosity='0' + ModTime=1753886315 + Library='' + LibLocation='Project' + ModSinceLib=true + $end 'PCB_Material' + $begin 'Ceramic_material' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=1 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + $begin 'AttachedData' + $begin 'MatAppearanceData' + property_data='appearance_data' + Red=0 + Green=100 + Blue=0 + Transparency=0 + $end 'MatAppearanceData' + $end 'AttachedData' + $begin 'ModifierData' + $begin 'ThermalModifierData' + modifier_data='thermal_modifier_data' + $begin 'all_thermal_modifiers' + $end 'all_thermal_modifiers' + $end 'ThermalModifierData' + $end 'ModifierData' + permittivity='1' + permeability='1' + conductivity='0' + dielectric_loss_tangent='0' + magnetic_loss_tangent='0' + thermal_conductivity='15' + mass_density='2500' + specific_heat='910' + youngs_modulus='0' + poissons_ratio='0' + thermal_expansion_coefficient='0' + $begin 'thermal_material_type' + property_type='ChoiceProperty' + Choice='Solid' + $end 'thermal_material_type' + diffusivity='0.8' + molecular_mass='0' + viscosity='0' + ModTime=1753886315 + Library='' + LibLocation='Project' + ModSinceLib=true + $end 'Ceramic_material' + $end 'Materials' + $begin 'SurfaceMaterials' + $begin 'Steel-oxidised-surface' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=2 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + surface_emissivity='0.8' + ModTime=1461288057 + Library='SurfaceMaterials' + LibLocation='SysLibrary' + ModSinceLib=false + $end 'Steel-oxidised-surface' + $begin 'Shellac dull-surface' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=2 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + surface_emissivity='0.91' + ModTime=1461288057 + Library='SurfaceMaterials' + LibLocation='SysLibrary' + ModSinceLib=false + $end 'Shellac dull-surface' + $begin 'Shellac-Bright-surface' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=2 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + surface_emissivity='0.82' + ModTime=1461288057 + Library='SurfaceMaterials' + LibLocation='SysLibrary' + ModSinceLib=false + $end 'Shellac-Bright-surface' + $begin 'Soft Rubber-Gray-surface' + CoordinateSystemType='Cartesian' + BulkOrSurfaceType=2 + $begin 'PhysicsTypes' + set('Thermal') + $end 'PhysicsTypes' + surface_emissivity='0.86' + ModTime=1461288057 + Library='SurfaceMaterials' + LibLocation='SysLibrary' + ModSinceLib=false + $end 'Soft Rubber-Gray-surface' + $end 'SurfaceMaterials' + $begin 'Scripts' + $end 'Scripts' + $begin 'Symbols' + $begin 'IcepakDesign1' + ModTime=1488469606 + Library='' + ModSinceLib=false + LibLocation='Project' + HighestLevel=1 + Normalize=true + InitialLevels(0, 1) + $begin 'Graphics' + Rect(0, 0, 0, 0, 0.00254, 0.00254, 0.00508, 0.00508, 0, 0, 0) + Rect(0, 1, 0, 0, 0.000423333333333333, 0.00254, 0.000423333333333333, 0.000423333333333334, 0, 0, 0) + $end 'Graphics' + $end 'IcepakDesign1' + $end 'Symbols' + $begin 'DefInfo' + IcepakDesign1(1002, 0, 0, 0, '', 1488469606, '', 'IcepakDesign1', '', '', '', '', '', 'Design.bmp', '', 'Project', '', '', 1488469606, '', 0, 0) + $end 'DefInfo' + $begin 'Compdefs' + $begin 'IcepakDesign1' + Library='' + CircuitEnv=0 + Refbase='U' + NumParts=1 + ModSinceLib=true + $begin 'Properties' + TextProp('Representation', 'SRD', '', 'IcepakDesign1') + TextProp('Owner', 'SRD', '', 'Icepak') + $end 'Properties' + CompExtID=6 + $begin 'Parameters' + ButtonProp('CosimDefinition', 'D', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + MenuProp('CoSimulator', 'D', '', 'DefaultNetlist', 0) + $end 'Parameters' + $begin 'CosimDefinitions' + $begin 'CosimDefinition' + CosimulatorType=4 + CosimDefName='DefaultNetlist' + IsDefinition=true + Connect=true + Data() + GRef() + $end 'CosimDefinition' + DefaultCosim='DefaultNetlist' + $end 'CosimDefinitions' + $end 'IcepakDesign1' + $end 'Compdefs' + $end 'Definitions' + DesignIDServer=2 + MoveBackwards=false + $begin 'IcepakModel' + RepRewriteV2=true + Name='IcepakDesign1' + DesignID=0 + 'Perform Minimal validation'=true + 'Default Fluid Material'='air' + 'Default Solid Material'='Al-Extruded' + 'Default Surface Material'='Steel-Oxidised-surface' + AmbientTemperature='20cel' + AmbientPressure='0n_per_meter_sq' + AmbientRadiationTemperature='20cel' + 'Gravity Vector CS ID'=1 + 'Gravity Vector Axis'='Y' + Positive=false + ExportOnSimulationComplete=false + ExportDirectory='' + SherlockExportOnSimulationComplete=false + SherlockExportAsFatigue=true + SherlockExportDirectory='D:/Siva_Coding/Graphics_Card.aedtexport/IcepakDesign1/' + AutoLaunchMeshViewer=true + MeshCadAsLightWeight=true + EnableTransitionTemplate=false + TempSecondaryGradientSkewMesh=false + EnableMeshByLayerFor2DMLM=false + BoundaryBasedMeshRefinement=false + EnableAltitudeEffects=false + UpdateFanCurve=false + Altitude='0meter' + EnableIdealGasLaw=false + OperatingPressure='101325n_per_meter_sq' + EnableOperatingDensity=false + OperatingDensity='1.225kg_per_m3' + AppendTemplateToFieldsSummaryReport=false + EnableLoadSolution=false + $begin 'SolutionTypeOption' + SolutionTypeOption='SteadyState' + ProblemOption='TemperatureAndFlow' + $end 'SolutionTypeOption' + $begin 'OutputVariable' + NextUniqueID=0 + MoveBackwards=false + $end 'OutputVariable' + $begin 'ModelSetup' + $begin 'DesignDatasets' + NextUniqueID=0 + MoveBackwards=false + DatasetType='DesignDatasetType' + $begin 'DatasetDefinitions' + $end 'DatasetDefinitions' + $end 'DesignDatasets' + VariableOrders[0:] + $begin 'Editor3D Doc Preferences' + BackgroundColorVersion=1 + 'Plane Background'=0 + 'Need Lights'=true + 'Ambient Light'=9671571 + 'Num Lights'=4 + Light0[4: 6710886, 0, -1, -0.150000005960464] + Light1[4: 6710886, -0.600000023841858, 0.100000001490116, -0.5] + Light2[4: 6710886, 0.5, 0.100000001490116, -0.5] + Light3[4: 6710886, 0.200000002980232, 0.400000005960464, 1] + Ver=2 + $end 'Editor3D Doc Preferences' + SnapMode=31 + WorkingCS=1 + $begin 'GeometryCore' + BlockVersionID=3 + DataVersion=170 + NativeKernel='PARASOLID' + NativeKernelVersionID=25 + Units='mm' + ModelExtents=10000 + InstanceID=-1 + $begin 'ValidationOptions' + EntityCheckLevel='Basic' + IgnoreUnclassifiedObjects=true + SkipIntersectionChecks=true + $end 'ValidationOptions' + ContainsGeomLinkUDM=false + $begin 'GeometryOperations' + BlockVersionID=2 + $begin 'AnsoftRangedIDServerManager' + $begin 'AnsoftRangedIDServer' + IDServerObjectTypeID=0 + IDServerRangeMin=0 + IDServerRangeMax=2146483647 + NextUniqueID=609 + MoveBackwards=false + $end 'AnsoftRangedIDServer' + $begin 'AnsoftRangedIDServer' + IDServerObjectTypeID=1 + IDServerRangeMin=2146483648 + IDServerRangeMax=2146485547 + NextUniqueID=2146483654 + MoveBackwards=false + $end 'AnsoftRangedIDServer' + $end 'AnsoftRangedIDServerManager' + StartBackGroundFaceID=2146483648 + $begin 'CoordinateSystems' + $end 'CoordinateSystems' + $begin 'OperandCSs' + $end 'OperandCSs' + $begin 'SubModelDefinitions' + $end 'SubModelDefinitions' + $begin 'Groups' + $begin 'Group' + GroupID=477 + $begin 'Attributes' + Name='graphics_card_simple' + ParentGroupID=-1 + $end 'Attributes' + $end 'Group' + $end 'Groups' + $begin 'UserDefinedModels' + $end 'UserDefinedModels' + $begin 'OperandUserDefinedModels' + $end 'OperandUserDefinedModels' + $begin 'ToplevelParts' + $begin 'GeometryPart' + $begin 'Attributes' + Name='Region' + Flags='Wireframe#' + Color='(0 0 0)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=-1 + MaterialValue='"air"' + SurfaceMaterialValue='""' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='Region' + ID=5 + ReferenceCoordSystemID=1 + $begin 'RegionParameters' + KernelVersion=9 + '+XPaddingType'='Percentage Offset' + '+XPadding'='50' + '-XPaddingType'='Percentage Offset' + '-XPadding'='50' + '+YPaddingType'='Percentage Offset' + '+YPadding'='50' + '-YPaddingType'='Percentage Offset' + '-YPadding'='50' + '+ZPaddingType'='Percentage Offset' + '+ZPadding'='50' + '-ZPaddingType'='Percentage Offset' + '-ZPadding'='50' + $begin 'BoxForVirtualObjects' + LowPoint[3: 1, 1, 1] + HighPoint[3: -1, -1, -1] + $end 'BoxForVirtualObjects' + $end 'RegionParameters' + ParentPartID=6 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=6 + StartFaceID=7 + StartEdgeID=13 + StartVertexID=25 + NumNewFaces=6 + NumNewEdges=12 + NumNewVertices=8 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + IsXZ2DModeler=false + $end 'OperationIdentity' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='SERIAL_PORT' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Al-Extruded"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=33 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=34 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000034.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='MEMORY1' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Ceramic_material"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=61 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=62 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000062.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='MEMORY1_1' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Ceramic_material"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=89 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=90 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000090.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='CAPACITOR' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Ceramic_material"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=117 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=118 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=4 + NumWires=0 + NumLoops=4 + NumCoedges=12 + NumEdges=6 + NumVertices=4 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000118.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='CAPACITOR_1' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Ceramic_material"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=133 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=134 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=4 + NumWires=0 + NumLoops=4 + NumCoedges=12 + NumEdges=6 + NumVertices=4 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000134.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='KB' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Al-Extruded"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=149 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=150 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000150.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='HEAT_SINK' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Al-Extruded"' + SurfaceMaterialValue='"Soft Rubber-Gray-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=177 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=178 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=42 + NumWires=0 + NumLoops=42 + NumCoedges=240 + NumEdges=120 + NumVertices=80 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000178.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[1: 581] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='CPU' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Al-Extruded"' + SurfaceMaterialValue='"Steel-oxidised-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=421 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=422 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000422.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='ALPHA_MAIN_PCB' + Flags='' + Color='(175 175 175)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=477 + MaterialValue='"Al-Extruded"' + SurfaceMaterialValue='"Steel-oxidised-surface"' + SolveInside=true + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='NativeBody' + ID=449 + ReferenceCoordSystemID=1 + $begin 'NativeBodyParameters' + KernelVersion=9 + SourceFile='D:\\AnsysEM\\AnsysEM18.1\\Win64\\Examples\\Icepak\\Graphics Card\\graphics_card_simple.stp' + $end 'NativeBodyParameters' + ParentPartID=450 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=-1 + StartFaceID=-1 + StartEdgeID=-1 + StartVertexID=-1 + NumNewFaces=0 + NumNewEdges=0 + NumNewVertices=0 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + BodyType='BRepBody' + $begin 'BodyBlock' + BodyFileNamesVec[1: '0000450.x_b'] + $end 'BodyBlock' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='Box1' + Flags='NonModel#Wireframe#' + Color='(255 0 0)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=-1 + MaterialValue='""' + SurfaceMaterialValue='""' + SolveInside=false + ShellElement=false + ShellElementThickness='0mm' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='Box' + ID=497 + ReferenceCoordSystemID=1 + $begin 'BoxParameters' + KernelVersion=9 + XPosition='-72mm' + YPosition='-5mm' + ZPosition='-63mm' + XSize='67mm' + YSize='38mm' + ZSize='52mm' + $end 'BoxParameters' + ParentPartID=498 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=498 + StartFaceID=499 + StartEdgeID=505 + StartVertexID=517 + NumNewFaces=6 + NumNewEdges=12 + NumNewVertices=8 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + $end 'OperationIdentity' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[1: 553] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='MeshRegion1_SubRegion' + Flags='NonModel#Wireframe#' + Color='(255 0 0)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=-1 + MaterialValue='""' + SurfaceMaterialValue='""' + SolveInside=true + ShellElement=false + ShellElementThickness='nan ' + ReferenceTemperature='20cel' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='SubRegion' + ID=553 + ReferenceCoordSystemID=1 + $begin 'SubRegionParameters' + KernelVersion=24 + '+XPaddingType'='Absolute Offset' + '+XPadding'='0mm' + '-XPaddingType'='Absolute Offset' + '-XPadding'='0mm' + '+YPaddingType'='Absolute Offset' + '+YPadding'='0mm' + '-YPaddingType'='Absolute Offset' + '-YPadding'='0mm' + '+ZPaddingType'='Absolute Offset' + '+ZPadding'='0mm' + '-ZPaddingType'='Absolute Offset' + '-ZPadding'='0mm' + $begin 'BoxForVirtualObjects' + LowPoint[3: 1, 1, 1] + HighPoint[3: -1, -1, -1] + $end 'BoxForVirtualObjects' + SubRegionParts[1: 498] + SubRegionSubmodels[0:] + $end 'SubRegionParameters' + ParentPartID=554 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=554 + StartFaceID=555 + StartEdgeID=561 + StartVertexID=573 + NumNewFaces=6 + NumNewEdges=12 + NumNewVertices=8 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + IsXZ2DModeler=false + $end 'OperationIdentity' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $begin 'GeometryPart' + $begin 'Attributes' + Name='MeshRegion2_SubRegion' + Flags='NonModel#Wireframe#' + Color='(143 175 143)' + Transparency=0 + PartCoordinateSystem=1 + UDMId=-1 + GroupId=-1 + MaterialValue='"air"' + SurfaceMaterialValue='""' + SolveInside=true + ShellElement=false + ShellElementThickness='nan ' + ReferenceTemperature='nan ' + IsMaterialEditable=true + IsSurfaceMaterialEditable=true + UseMaterialAppearance=false + IsLightweight=false + IsAlwaysHidden=false + $end 'Attributes' + $begin 'PhysicsAttributes' + SuppressedForPhysics='False' + SuppressedForPhysicsEditable=true + $end 'PhysicsAttributes' + $begin 'Operations' + $begin 'Operation' + OperationType='SubRegion' + ID=581 + ReferenceCoordSystemID=1 + $begin 'SubRegionParameters' + KernelVersion=25 + '+XPaddingType'='Percentage Offset' + '+XPadding'='1' + '-XPaddingType'='Percentage Offset' + '-XPadding'='1' + '+YPaddingType'='Percentage Offset' + '+YPadding'='1' + '-YPaddingType'='Percentage Offset' + '-YPadding'='1' + '+ZPaddingType'='Percentage Offset' + '+ZPadding'='1' + '-ZPaddingType'='Percentage Offset' + '-ZPadding'='1' + $begin 'BoxForVirtualObjects' + LowPoint[3: 1, 1, 1] + HighPoint[3: -1, -1, -1] + $end 'BoxForVirtualObjects' + SubRegionParts[1: 178] + SubRegionSubmodels[0:] + $end 'SubRegionParameters' + ParentPartID=582 + ReferenceUDMID=-1 + IsSuppressed=false + $begin 'OperationIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=582 + StartFaceID=583 + StartEdgeID=589 + StartVertexID=601 + NumNewFaces=6 + NumNewEdges=12 + NumNewVertices=8 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + IsXZ2DModeler=false + $end 'OperationIdentity' + $end 'Operation' + $end 'Operations' + $begin 'SubregionDependencyInformation' + ChildSubregions[0:] + $end 'SubregionDependencyInformation' + $end 'GeometryPart' + $end 'ToplevelParts' + $begin 'OperandParts' + $end 'OperandParts' + $begin 'Planes' + $begin 'GeometryPlane' + $begin 'Attributes' + Name='Plane1' + Color='(143 175 143)' + $end 'Attributes' + $begin 'Operation' + OperationType='Plane' + ID=496 + ReferenceCoordSystemID=1 + $begin 'PlaneParameters' + KernelVersion=9 + PlaneBaseX='0mm' + PlaneBaseY='1.6mm' + PlaneBaseZ='-55mm' + PlaneNormalX='0mm' + PlaneNormalY='0mm' + PlaneNormalZ='5mm' + $end 'PlaneParameters' + ParentPartID=-1 + ReferenceUDMID=-1 + $end 'Operation' + $end 'GeometryPlane' + $end 'Planes' + $begin 'Points' + $begin 'GeometryPoint' + $begin 'Attributes' + Name='CPU_Monitor' + Color='(143 175 143)' + $end 'Attributes' + $begin 'Operation' + OperationType='Point' + ID=482 + ReferenceCoordSystemID=1 + $begin 'PointParameters' + KernelVersion=9 + PointX='-37mm' + PointY='3.086mm' + PointZ='-43mm' + $end 'PointParameters' + ParentPartID=-1 + ReferenceUDMID=-1 + $end 'Operation' + $end 'GeometryPoint' + $begin 'GeometryPoint' + $begin 'Attributes' + Name='Memory_Monitor' + Color='(143 175 143)' + $end 'Attributes' + $begin 'Operation' + OperationType='Point' + ID=483 + ReferenceCoordSystemID=1 + $begin 'PointParameters' + KernelVersion=9 + PointX='-35mm' + PointY='3.6mm' + PointZ='-86mm' + $end 'PointParameters' + ParentPartID=-1 + ReferenceUDMID=-1 + $end 'Operation' + $end 'GeometryPoint' + $begin 'GeometryPoint' + $begin 'Attributes' + Name='Point1' + Color='(143 175 143)' + $end 'Attributes' + $begin 'Operation' + OperationType='Point' + ID=485 + ReferenceCoordSystemID=1 + $begin 'PointParameters' + KernelVersion=9 + PointX='80mm' + PointY='14.243mm' + PointZ='-55mm' + $end 'PointParameters' + ParentPartID=-1 + ReferenceUDMID=-1 + $end 'Operation' + $end 'GeometryPoint' + $end 'Points' + $begin 'GeometryEntityLists' + $end 'GeometryEntityLists' + $begin 'RegionIdentity' + $begin 'Topology' + NumLumps=1 + NumShells=1 + NumFaces=6 + NumWires=0 + NumLoops=6 + NumCoedges=24 + NumEdges=12 + NumVertices=8 + $end 'Topology' + BodyID=6 + StartFaceID=7 + StartEdgeID=13 + StartVertexID=25 + NumNewFaces=6 + NumNewEdges=12 + NumNewVertices=8 + FaceNameAndIDMap() + EdgeNameAndIDMap() + VertexNameAndIDMap() + IsXZ2DModeler=false + $end 'RegionIdentity' + $begin 'CachedNames' + $begin 'allobjects' + allobjects(-1) + $end 'allobjects' + $begin 'alpha_main_pcb' + alpha_main_pcb(-1) + $end 'alpha_main_pcb' + $begin 'box' + box(1) + $end 'box' + $begin 'capacitor' + capacitor(-1) + $end 'capacitor' + $begin 'capacitor_' + capacitor_(1) + $end 'capacitor_' + $begin 'cpu' + cpu(-1) + $end 'cpu' + $begin 'cpu_monitor' + cpu_monitor(-1) + $end 'cpu_monitor' + $begin 'global' + global(-1) + $end 'global' + $begin 'graphics_card_simple' + graphics_card_simple(-1) + $end 'graphics_card_simple' + $begin 'heat_sink' + heat_sink(-1) + $end 'heat_sink' + $begin 'kb' + kb(-1) + $end 'kb' + $begin 'memory' + memory(1) + $end 'memory' + $begin 'memory1_' + memory1_(1) + $end 'memory1_' + $begin 'memory_monitor' + memory_monitor(-1) + $end 'memory_monitor' + $begin 'meshregion1_subregion' + meshregion1_subregion(-1) + $end 'meshregion1_subregion' + $begin 'meshregion2_subregion' + meshregion2_subregion(-1) + $end 'meshregion2_subregion' + $begin 'model' + model(-1) + $end 'model' + $begin 'plane' + plane(1) + $end 'plane' + $begin 'point' + point(1) + $end 'point' + $begin 'region' + region(-1) + $end 'region' + $begin 'serial_port' + serial_port(-1) + $end 'serial_port' + $end 'CachedNames' + $end 'GeometryOperations' + $begin 'GeometryDependencies' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 5) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 33) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 61) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 89) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 117) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 133) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 149) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 177) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 421) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 449) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 497) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 553) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryBodyOperation', 581) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryOperation', 496) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryOperation', 482) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryOperation', 483) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $begin 'DependencyInformation' + NumParents=1 + DependencyObject('GeometryOperation', 485) + DependencyObject('CoordinateSystem', 1) + $end 'DependencyInformation' + $end 'GeometryDependencies' + $end 'GeometryCore' + $begin 'AssignedEntities' + AssignedObject[7: 62, 90, 150, 178, 422, 554, 582] + $begin 'AssignedFace' + kID=10 + $begin 'FaceData' + ParentObjectID=6 + NormalValid=true + FaceNormal(-1, -0, -0) + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=16720 + FcUVMid(-240, 14, -55) + $begin 'FcTolVts' + TolVt(-240, -24, 55, 5e-07) + TolVt(-240, 52, 55, 5e-07) + TolVt(-240, 52, -165, 5e-07) + TolVt(-240, -24, -165, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' + $begin 'AssignedFace' + kID=12 + $begin 'FaceData' + ParentObjectID=6 + NormalValid=true + FaceNormal(1, 0, 0) + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=16720 + FcUVMid(80, 14, -55) + $begin 'FcTolVts' + TolVt(80, 52, -165, 5e-07) + TolVt(80, 52, 55, 5e-07) + TolVt(80, -24, 55, 5e-07) + TolVt(80, -24, -165, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' + $begin 'AssignedFace' + kID=155 + $begin 'FaceData' + ParentObjectID=150 + NormalValid=false + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=179.2 + FcUVMid(-153.6, 1.6, -102) + $begin 'FcTolVts' + TolVt(-147.2, 1.6, -109, 5e-07) + TolVt(-147.2, 1.6, -95, 5e-07) + TolVt(-160, 1.6, -95, 5e-07) + TolVt(-160, 1.6, -109, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' + $begin 'AssignedFace' + kID=455 + $begin 'FaceData' + ParentObjectID=450 + NormalValid=false + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=17600 + FcUVMid(-80, 1.6, -55) + $begin 'FcTolVts' + TolVt(-160, 1.6, 0, 5e-07) + TolVt(0, 1.6, 0, 5e-07) + TolVt(0, 1.6, -110, 5e-07) + TolVt(-160, 1.6, -110, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' + $end 'AssignedEntities' + GroupByMaterial=true + GroupSheetByMaterial=true + GroupCompByDefID=true + DoNotOrganizeUnderGroup=true + DoNotOrganizeUnderComponent=false + OrganizeLightweight=false + ShowGroup=true + $begin 'LastUserInputs' + $end 'LastUserInputs' + $end 'ModelSetup' + $begin '3DComponent' + $begin 'NativeComponentVisualization' + $end 'NativeComponentVisualization' + $end '3DComponent' + $begin 'BoundarySetup' + $begin 'GlobalBoundData' + $end 'GlobalBoundData' + $begin 'Boundaries' + NextUniqueID=6 + MoveBackwards=false + $begin 'Grille1' + ID=0 + BoundType='Grille' + IsComponent=false + Faces(12) + 'Pressure Loss Type'='Coeff' + 'Free Area Ratio'='0.8' + 'Resistance Type'='Perforated Thin Vent' + 'External Rad. Temperature'='AmbientTemp' + 'External Total Pressure'='AmbientPressure' + DimUnits[2: '', ''] + X() + Y() + $end 'Grille1' + $begin 'Opening1' + ID=1 + BoundType='Opening' + IsComponent=false + Faces(10) + Temperature='AmbientTemp' + 'External Rad. Temperature'='AmbientRadTemp' + 'Inlet Type'='Velocity' + 'Static Pressure'='AmbientPressure' + 'X Velocity'='2m_per_sec' + 'Y Velocity'='0m_per_sec' + 'Z Velocity'='0m_per_sec' + 'No Reverse Flow'=false + $end 'Opening1' + $begin 'CPU' + ID=2 + BoundType='Block' + IsComponent=false + Objects(422, 150, 178) + ParentBndID=-1 + 'Block Type'='Solid' + 'Use External Conditions'=false + 'Use Total Power'=true + 'Total Power'='4W' + $end 'CPU' + $begin 'Memory' + ID=3 + BoundType='Block' + IsComponent=false + Objects(62, 90) + ParentBndID=-1 + 'Block Type'='Solid' + 'Use External Conditions'=false + 'Use Total Power'=false + 'Power Density'='5w_per_m3' + $end 'Memory' + $begin 'Source1' + ID=5 + BoundType='Source' + IsComponent=false + Faces(155) + 'Thermal Condition'='Total Power' + 'Total Power'='1W' + 'Surface Heat'='0mW_per_m2' + Temperature='AmbientTemp' + $begin 'Radiation' + Radiate=false + $end 'Radiation' + 'Voltage/Current - Enabled'=false + 'Voltage/Current Option'='Current' + Current='0A' + Voltage='0V' + $end 'Source1' + $end 'Boundaries' + $begin 'ProductSpecificData' + $end 'ProductSpecificData' + $end 'BoundarySetup' + $begin 'Monitor' + $begin 'IcepakMonitors' + NextUniqueID=4 + MoveBackwards=false + $end 'IcepakMonitors' + $end 'Monitor' + $begin 'MeshRegion' + $begin 'MeshSetup' + NextUniqueID=3 + MoveBackwards=false + $begin 'Global' + DType='RegionT' + ID=0 + IsComponent=false + MeshMethod='MesherHD' + UserSpecifiedSettings=true + ComputeGap=true + MaxElementSizeX='16mm' + MaxElementSizeY='3.5mm' + MaxElementSizeZ='11mm' + MinElementsInGap='3' + MinElementsOnEdge='2' + MaxSizeRatio='2' + NoOGrids=false + EnableMLM=true + EnforeMLMType='3D' + MaxLevels='2' + BufferLayers='0' + UniformMeshParametersType='Average' + StairStepMeshing=false + MinGapX='1mm' + MinGapY='1mm' + MinGapZ='1mm' + Objects(6) + StairStepSliderMeshing=false + FacetLevel='3' + ProximitySizeFunction=true + CurvatureSizeFunction=true + EnableTransition=false + OptimizePCBMesh=true + Enable2DCutCell=false + EnforceCutCellMeshing=false + Enforce2dot5DCutCell=false + $end 'Global' + $begin 'MeshRegion1' + DType='RegionT' + ID=1 + IsComponent=false + Enable=true + MeshMethod='MesherHD' + UserSpecifiedSettings=true + MaxElementSizeX='3.35mm' + MaxElementSizeY='1.75mm' + MaxElementSizeZ='2.65mm' + MinElementsInGap='3' + MinElementsOnEdge='2' + MaxSizeRatio='2' + NoOGrids=false + EnableMLM=true + EnforeMLMType='3D' + MaxLevels='2' + BufferLayers='0' + UniformMeshParametersType='Average' + StairStepMeshing=false + '2DMLMType'='2DMLM_None' + MinGapX='1mm' + MinGapY='1mm' + MinGapZ='1mm' + Objects(554) + ProximitySizeFunction=true + CurvatureSizeFunction=true + EnableTransition=false + OptimizePCBMesh=true + Enable2DCutCell=false + EnforceCutCellMeshing=false + Enforce2dot5DCutCell=false + $end 'MeshRegion1' + $begin 'MeshRegion2' + DType='RegionT' + ID=2 + IsComponent=false + Enable=true + MeshMethod='MesherHD' + UserSpecifiedSettings=false + MeshRegionResolution=3 + GeometryBasedMeshing=false + MinGapX='1mm' + MinGapY='1mm' + MinGapZ='1mm' + Objects(582) + ProximitySizeFunction=true + CurvatureSizeFunction=true + EnableTransition=false + OptimizePCBMesh=true + Enable2DCutCell=false + EnforceCutCellMeshing=false + Enforce2dot5DCutCell=false + $end 'MeshRegion2' + $end 'MeshSetup' + $end 'MeshRegion' + $begin 'AnalysisSetup' + $begin 'DesignMeshLink' + ImportMesh=false + $end 'DesignMeshLink' + $begin 'SolveSetups' + NextUniqueID=2 + MoveBackwards=false + $begin 'Setup1' + ID=0 + SetupType='IcepakSteadyState' + Enabled=true + $begin 'MeshLink' + ImportMesh=false + $end 'MeshLink' + 'Flow Regime'='Turbulent' + 'Turbulent Model Eqn'='ZeroEquation' + 'Include Temperature'=true + 'Include Flow'=true + 'Include Gravity'=true + 'Include Solar'=false + 'Solution Initialization - X Velocity'='0m_per_sec' + 'Solution Initialization - Y Velocity'='0m_per_sec' + 'Solution Initialization - Z Velocity'='0m_per_sec' + 'Solution Initialization - Temperature'='AmbientTemp' + 'Solution Initialization - Turbulent Kinetic Energy'='0' + 'Solution Initialization - Turbulent Dissipation Rate'='0' + 'Solution Initialization - Specific Dissipation Rate'='0' + 'Solution Initialization - Use Model Based Flow Initialization'=false + 'Convergence Criteria - Flow'='0.001' + 'Convergence Criteria - Energy'='1e-07' + 'Convergence Criteria - Turbulent Kinetic Energy'='1e-07' + 'Convergence Criteria - Turbulent Dissipation Rate'='1e-07' + 'Convergence Criteria - Specific Dissipation Rate'='0.001' + 'Convergence Criteria - Discrete Ordinates'='1e-06' + 'Convergence Criteria - Joule Heating'='1e-07' + 'GPU Convergence Criteria - Flow'='0.001' + 'GPU Convergence Criteria - Energy'='1e-05' + 'GPU Convergence Criteria - Turbulent Kinetic Energy'='0.001' + 'GPU Convergence Criteria - Turbulent Dissipation Rate'='0.001' + 'GPU Convergence Criteria - Specific Dissipation Rate'='0.001' + 'GPU Convergence Criteria - Discrete Ordinates'='1e-05' + 'GPU Convergence Criteria - Joule Heating'='1e-07' + IsEnabled=false + 'Radiation Model'='Off' + 'Solar Radiation Model'='Solar Radiation Calculator' + 'Solar Enable Participating Solids'=false + 'Solar Radiation - Scattering Fraction'='0' + 'Solar Radiation - North X'='0' + 'Solar Radiation - North Y'='0' + 'Solar Radiation - North Z'='0' + 'Solar Radiation - Day'=1 + 'Solar Radiation - Month'=1 + 'Solar Radiation - Hours'=0 + 'Solar Radiation - Minutes'=0 + 'Solar Radiation - GMT'='0' + 'Solar Radiation - Latitude'='0' + 'Solar Radiation - Latitude Direction'='North' + 'Solar Radiation - Longitude'='0' + 'Solar Radiation - Longitude Direction'='East' + 'Solar Radiation - Ground Reflectance'='0' + 'Solar Radiation - Sunshine Fraction'='0' + 'Under-relaxation - Pressure'='0.3' + 'Under-relaxation - Momentum'='0.7' + 'Under-relaxation - Temperature'='1' + 'Under-relaxation - Turbulent Kinetic Energy'='0.8' + 'Under-relaxation - Turbulent Dissipation Rate'='0.8' + 'Under-relaxation - Specific Dissipation Rate'='0.8' + 'Under-relaxation - Joule Heating'='1' + 'Under-relaxation - Body Force'='1' + 'Under-relaxation - Turbulent Viscosity'='1' + 'Discretization Scheme - Pressure'='Standard' + 'Discretization Scheme - Momentum'='First' + 'Discretization Scheme - Temperature'='First' + 'Secondary Gradient'=false + 'Discretization Scheme - Turbulent Kinetic Energy'='First' + 'Discretization Scheme - Turbulent Dissipation Rate'='First' + 'Discretization Scheme - Specific Dissipation Rate'='First' + 'Discretization Scheme - Discrete Ordinates'='First' + 'Linear Solver Type - Pressure'='flex' + 'Linear Solver Type - Momentum'='flex' + 'Linear Solver Type - Temperature'='flex' + 'Linear Solver Type - Turbulent Kinetic Energy'='flex' + 'Linear Solver Type - Turbulent Dissipation Rate'='flex' + 'Linear Solver Type - Specific Dissipation Rate'='flex' + 'Linear Solver Type - Joule Heating'='F' + 'Linear Solver Termination Criterion - Pressure'='0.1' + 'Linear Solver Termination Criterion - Momentum'='0.1' + 'Linear Solver Termination Criterion - Temperature'='0.1' + 'Linear Solver Termination Criterion - Turbulent Kinetic Energy'='0.1' + 'Linear Solver Termination Criterion - Turbulent Dissipation Rate'='0.1' + 'Linear Solver Termination Criterion - Specific Dissipation Rate'='0.1' + 'Linear Solver Termination Criterion - Joule Heating'='1e-09' + 'Linear Solver Residual Reduction Tolerance - Pressure'='0.1' + 'Linear Solver Residual Reduction Tolerance - Momentum'='0.1' + 'Linear Solver Residual Reduction Tolerance - Temperature'='0.1' + 'Linear Solver Residual Reduction Tolerance - Turbulent Kinetic Energy'='0.1' + 'Linear Solver Residual Reduction Tolerance - Turbulent Dissipation Rate'='0.1' + 'Linear Solver Residual Reduction Tolerance - Specific Dissipation Rate'='0.1' + 'Linear Solver Residual Reduction Tolerance - Joule Heating'='1e-09' + 'Maximum Cycles'='30' + 'Linear Solver Stabilization - Pressure'='None' + 'Linear Solver Stabilization - Temperature'='None' + 'Linear Solver Stabilization - Joule Heating'='None' + 'Coupled pressure-velocity formulation'=false + 'Turn off auto-pairing for grid interface creation'=false + '2D Profile Interpolation Method'='Inverse Distance Weighted' + 'Frozen Flow Simulation'=false + 'TEC Coupling'=false + 'Sequential Solve of Flow and Energy Equations'=false + 'Convergence Criteria - Max Iterations'=100 + $end 'Setup1' + $end 'SolveSetups' + $end 'AnalysisSetup' + $begin 'Optimetrics' + $begin 'OptimetricsSetups' + NextUniqueID=0 + MoveBackwards=false + $end 'OptimetricsSetups' + $end 'Optimetrics' + $begin 'Solutions' + $begin 'FieldsSummarySetting' + $end 'FieldsSummarySetting' + $end 'Solutions' + $begin 'FieldsReporter' + $begin 'FieldsCalculator' + Line_Discretization=1000 + 'Show Stack'=true + $end 'FieldsCalculator' + $begin 'PlotDefaults' + Default_SolutionId=15 + Default_PlotFolder='Automatic' + $end 'PlotDefaults' + $begin 'FieldsPlotManagerID' + NextUniqueID=5 + MoveBackwards=false + NumQuantityType=1 + $begin 'QuantityFolder_1' + PlotFolder='Temperature' + PlotFolderInstance=1 + FolderSettingsType=11 + 'Real time mode'=true + $begin 'ColorMapSettings' + ColorMapType='Spectrum' + SpectrumType='Rainbow' + UniformColor(127, 255, 255) + RampColor(255, 127, 127) + $end 'ColorMapSettings' + $begin 'Scale3DSettings' + unit=80 + m_nLevels=15 + minvalue=20.3477725982666 + maxvalue=57.7943649291992 + log=false + IntrinsicMin=20.3477725982666 + IntrinsicMax=57.7943649291992 + LimitFieldValuePrecision=false + FieldValuePrecisionDigits=4 + dB=false + AnimationStaticScale=false + ScaleType=0 + UserSpecifyValues(16, 20.3477725982666, 22.8442115783691, 25.3406524658203, 27.8370914459229, 30.3335304260254, 32.8299713134766, 35.3264083862305, 37.8228530883789, 40.3192901611328, 42.8157272338867, 45.3121719360352, 47.8086090087891, 50.305046081543, 52.8014907836914, 55.2979278564453, 57.7943649291992) + ValueNumberFormatTypeAuto=1 + ValueNumberFormatTypeScientific=true + ValueNumberFormatWidth=12 + ValueNumberFormatPrecision=4 + $end 'Scale3DSettings' + $begin 'Marker3DSettings' + MarkerType=9 + MarkerMapSize=true + MarkerMapColor=false + MarkerSize=0.25 + $end 'Marker3DSettings' + $begin 'Arrow3DSettings' + ArrowType=1 + ArrowMapSize=true + ArrowMapColor=true + ShowArrowTail=true + ArrowSize=0.25 + ArrowMinMagnitude=19.8477725982666 + ArrowMaxMagnitude=58.2943649291992 + ArrowMagnitudeThreshold=19.8477725982666 + ArrowMagnitudeFilteringFlag=false + ArrowMinIntrinsicMagnitude=19.8477725982666 + ArrowMaxIntrinsicMagnitude=58.2943649291992 + $end 'Arrow3DSettings' + $end 'QuantityFolder_1' + NumPlots=1 + $begin 'PlotDefinition_1' + PlotDefinitionType='Mesh_field_type' + PlotName='Temperature1' + PlotDefinitionId=4 + VersionID=473 + SolutionId=15 + UserSpecifyName=0 + UserSpecifyFolder=0 + QuantityId=1 + PlotFolder='Temperature' + StreamlinePlot=false + AdjacentSidePlot=false + FullModelPlot=false + IntrinsicVar='' + FieldPlotGeometry(1, 128, 2, 1, 455) + FilterIds(0) + $begin 'PlotOnSurfaceSettings' + Filled=false + IsoValType='Fringe' + AddGrid=false + MapTransparency=true + Refinement=0 + Transparency=0 + SmoothingLevel=0 + ShadingType=0 + $begin 'Arrow3DSpacingSettings' + ArrowUniform=true + ArrowSpacing=2.91247320175171 + MinArrowSpacing=1.94164872169495 + MaxArrowSpacing=3.88329744338989 + $end 'Arrow3DSpacingSettings' + GridColor(255, 255, 255) + $end 'PlotOnSurfaceSettings' + EnableGaussianSmoothing=false + SurfaceOnly=false + $end 'PlotDefinition_1' + $end 'FieldsPlotManagerID' + $begin 'Report3dInGeomWnd' + Report3dNum=0 + $end 'Report3dInGeomWnd' + $begin 'Report2dInGeomWnd' + Report2dNum=0 + $end 'Report2dInGeomWnd' + $begin 'AntennaParametersInGeomWnd' + AntennaParametersNum=0 + $end 'AntennaParametersInGeomWnd' + AntennaParametersPlotTablesOrder() + $end 'FieldsReporter' + $begin 'SolutionManager' + $begin 'SimSetup' + TypeName='BaseSetup' + ID=14 + Name='Setup1' + $begin 'Solution' + ID=15 + Name='SteadyState' + $begin 'SimDataExtractor' + $begin 'QuantityIDs' + NextUniqueID=0 + MoveBackwards=false + IDMap() + $end 'QuantityIDs' + SimValue('Temperature', 1, 80, false, SimValueID=1083, 3, 0, 2, 0, false, false, 455, 1, 0, 1, 1, '', 0, 0) + $begin 'Sweeps' + $begin 'Sweep' + Variable='X' + Column='0' + Units='' + $end 'Sweep' + $end 'Sweeps' + $end 'SimDataExtractor' + $end 'Solution' + $end 'SimSetup' + $begin 'Version ID Map' + V=1085 + $begin 'Setup' + N='Setup1' + V=1084 + Soln(N='SteadyState', V=1085) + $end 'Setup' + $end 'Version ID Map' + $begin 'ID Map' + $begin 'Setup' + N='Setup1' + I=14 + Soln(N='SteadyState', I=15) + $end 'Setup' + $end 'ID Map' + ValidationCacheHeader='HDR18F0205928160286062711.tmp' + $end 'SolutionManager' + $begin 'UserDefinedSolutionMgr' + NextUniqueID=1000000 + MoveBackwards=false + $end 'UserDefinedSolutionMgr' + $begin 'DatasetSolutionMgr' + NextUniqueID=2000000 + MoveBackwards=false + $end 'DatasetSolutionMgr' + Notes=$begin_cdata$ $end_cdata$ + $begin 'AnimationSetups' + $end 'AnimationSetups' + CacheHeaderFile='HDR6EE53479217413415443.tmp' + $end 'IcepakModel' + $begin 'DataInstances' + DesignEditor='TopLevel' + Refdes('0', 'U1') + $begin 'CompInstances' + $begin 'Compinst' + ID='0' + Status='Status' + CompName='IcepakDesign1' + GatesInUse() + $begin 'Properties' + TextProp('ID', 'SRID', '', '0') + $end 'Properties' + $begin 'Parameters' + MenuProp('CoSimulator', 'OHD', '', 'DefaultNetlist', 0) + ButtonProp('CosimDefinition', 'OHD', '', 'Edit', 'Edit', 40501, ButtonPropClientData()) + $end 'Parameters' + $end 'Compinst' + $end 'CompInstances' + $begin 'Instance' + DesignEditor='IcepakDesign1' + ID='0' + $begin 'IcepakDesignInstance' + DesignInstanceID=1 + $begin 'WindowPosition' + $begin 'EditorWindow' + Circuit(Editor3d(View('View Orientation Gadget'=1, WindowPos(3, -1, -1, -9, -38, 200, 200, 992, 435), OrientationMatrix(0.00372929591685534, -0.00215311022475362, 0.0030449575278908, 0, 0.00372929591685534, 0.00215311022475362, -0.0030449575278908, 0, 0, 0.00430622044950724, 0.0030449575278908, 0, 0.246133506298065, 0.0344497710466385, -5.28414821624756, 1, 0, -1.55345916748047, 1.55345916748047, -1, 1, 0.520563125610352, 10.9551305770874), Drawings[12: 'Region', 'SERIAL_PORT', 'MEMORY1', 'MEMORY1_1', 'CAPACITOR', 'CAPACITOR_1', 'KB', 'HEAT_SINK', 'CPU', 'ALPHA_MAIN_PCB', 'Box1', 'MeshRegion2_SubRegion'], 'View Data'('Render Mode'=1, 'Show Ruler'=1, 'Coordinate Systems View Mode'=0, 'CS Triad View Mode'=0, 'Render Facets'=1, GridVisible=1, GridAutoAdjust=1, GridAutoExtents=1, GridType='Rect', GridStyle='Line', NumPixels=30, dXForGrid=20, dYForGrid=20, dZForGrid=20, dRForGrid=20, dThetaForGrid=10), ClipPlanes(ClipPlaneOptions(DisableWhenDrawingNewPlane=true, ForceOpqaueForUnclipped=false, ShowClipped=false, Transparency=0, HandleColor=16776960))))) + $end 'EditorWindow' + $end 'WindowPosition' + $begin 'ReportSetup' + $begin 'ReportManager' + $begin 'Reports' + $end 'Reports' + NextUniqueID=0 + MoveBackwards=false + $begin 'NextVersID' + NextUniqueID=0 + MoveBackwards=false + $end 'NextVersID' + $end 'ReportManager' + $begin 'Reports' + $end 'Reports' + $begin 'ReportsWindowInfoList' + $end 'ReportsWindowInfoList' + $end 'ReportSetup' + $begin 'Properties' + $end 'Properties' + $begin 'UserDefinedDocument' + $begin 'Data' + $end 'Data' + $end 'UserDefinedDocument' + $end 'IcepakDesignInstance' + $end 'Instance' + $begin 'SODInfo' + $begin 'IcepakDesign1' + $begin 'CosimDefinition' + CosimDefName='DefaultNetlist' + $begin 'SODInstanceMap' + $end 'SODInstanceMap' + SODComponentList() + $end 'CosimDefinition' + $end 'IcepakDesign1' + $end 'SODInfo' + $end 'DataInstances' + $begin 'WBSystemIDToDesignInstanceIDMap' + $end 'WBSystemIDToDesignInstanceIDMap' + $begin 'WBSysIDSysDetails' + $end 'WBSysIDSysDetails' + $begin 'WBConnIDConnDetails' + $end 'WBConnIDConnDetails' + $begin 'WBMaterialGuidDetails' + WBMaterialGuidMap() + $end 'WBMaterialGuidDetails' + $begin 'MinervaProjectSettingsBlk' + MinervaRemoteFilePath='' + FolderContainerString='' + $end 'MinervaProjectSettingsBlk' +$end 'AnsoftProject' +$begin 'AllReferencedFilesForProject' +$begin 'Design_0.setup/NativeGeometryFiles' +NumFiles= 9 +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000034.x_b +BIN000000008453 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE> +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ DS@@O SDL/TYSA_DENSITYP!"(#TUNIT=mmO"AEDT_EntityName_V1P#$(#S{Gz?O$AEDT_ExtentScale_V1Q%&'F(( $)*2 *+,+{GzMb?Eؿ +>-.+{GzI +?{Gz 2/0I +?{Gz *1V 2n34563/7nQ689:;3<=>? @+/:AB n7.CDMb?{GzC-EF7{GzMb?{GzD/G7H{GzI +?{GzG IJKLDnH0BD0I +?EؿBMN/KHn01LH {GzI +?EؿL OPGE0nQO8LIQRPSTULVWX+EQYLZCnQQ8EO[\Y]^_E@`a+Z[bEcnQ[8ZQdbef?ZghT+c+ZF{GzMb?EؿF,KcCMb?EؿKi?BGFnQi8KMIj?eb@K3 >-e@k@e?fY`_-><3NKUlg+<"N)N<>=BA4V+USPgB>l-lmn>WhngSUTKbh-Sg+TSgPZopq+hrnblstQr~8humvws vn^h-xt:hyz+Mb?Eؿ?y9Wxt+I +?Eؿ?z;{t|+Mb?{Gz?{}n=`~z|<~z.+I +?{Gz?~nJ{W|.=4| ++I +?{Gz4nN `.Qx842`nY4{Qy8`}7`x+Mb?{Gz?6p5+{GzI +?Eؿx8sy+{GzMb?{Gz?pnT-55 n+Mb?Eؿ?n4l5+I +?Eؿ3n+{GzMb?Eؿ?9nfpQ986fe@bEq+qoaZf-qoqLTp-aqE^sf-aoGX--^]YGas+]]_^/J~-_]Y={-JXAG~^+VXVJL-o+AJV/N4=-VAXBPWU-=<N3/_{+WnP~lyQ|8WmP8(#QeWQ{8~}Qm}8lrR/QflmuR.PAQughrS???QhsvuS???Qv8srQi-S???- +nXsp +Q8-vQjpS???Q8p9Qk9S???S???R*R+R,OSDL/TYSA_COLOURQd~Q}z8{R0Qc{}R1Qb`S???Qa4S???Q` 2S???Q2w8 Q_S???n+++1Qv82Q^+S???+ nŽS +1Qu8+Q]S???n+]++1Qt8Q\S???n‘k+k1Qs8Q[kS???kn“)e+)1Qr8kQZ)S???)!nk<,-k1Qq8)S???Qp8R(QnQ&R"P(#Q&RT SERIAL_PORTOAEDT_BODYFlagGroupColor_V1PQQmT SERIAL_PORTP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAME2,)) + rh?ʡEͿ?? 1 )2(k,+{GzMb?{Gz2'+{GzI +?Eؿ??2&+{GzI +?{Gz??2%+{Gz rh?ʡEͿ??R'R&R%R$R#R4S???S???OAEDT_EntityID_V1R)R2R3Rw-QM8B:iQI8GiORj9R8Q:8/6MR:R;Rd6R\5RR7R;<*# SJ([&P%8(#T 'Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000062.x_b +BIN000000008450 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) $*+2 +**,+пMb?Q?? >-.+пMb?Q 2/0пMb?(\ +1V 2n3456378nQ69:;<3=>?@A+7;>B0n8,CDп+[YMNfh^+XVS]7Q|+Q=?>JX|]-="3*?=3Q/d-p+>=Q37Y-/@F npodk/qz-qm@Fpz+mmAqBInf+@qA/3?-A@mM4-M[BA4m+feI^B[h-hn[n_Q}9hg3hs+ܿP(#Q'RTMEMORY1OAEDT_BODYFlagGroupColor_V1PQQmTMEMORY1P(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAME 1 *RC2'+пMb?(\2&l+ܿMb?(\?2(,+gfffffֿ?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) $*+2 +*,-+Mb?(\? >./+Mb?(\? 201?@A+0;@B n8+C0I1nQW9B;KX>=Y4BZ[\+="?*Y=?>I]^_+Z`G\>[-[an>5bc\`ZdBT.]+`\ed`\GHfg+Thi]H\.j-.kn\l^ ]hT_BY^-h_,_h]iIVm+^nnY.moQn}9^pkqrmqn_^sto9^uv+?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZS@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1QS&'(F)) *+3 +,-+QMb?? $./+QMb??? 01QMb? +2V3n4567489nQ7M:;<=4>??@A+8 <@BCn9C1QMb?C89QMb?1B9 QMb?BDE801nQDO:B<FGEHI@BJKL-0FMB nQFP:0DNMOPQ0A5I-O +J,POJMBRS+QOMJ?.-AH@IM5Q+5TnA.UIHAE0LVR+HAWLXRRBIVP-VYnIKSZRXLL0PS-XR[S;nPV\Q;L:S]Y7^\!S6Z+QMb???6 U\+QMb??Z"V\/+QMb??/#KZ +QMb?K _nJ.V/Q_J:K`aYbJOQP8EK+. an?5K QaI:.cT_d?>448Q.J+>?**enW> f+W2QeC:*ghijWin,*H -+,*22f*k-+QMb? 2 *2k[f+QMb?3-Wf ++QMb??[ln,X k-,2QlF:[mn3o, nn[WO ++[W2QnE:,pilqP:rs(#Qp6t,numvQiD:WuenwRqxQu5tWigpxRwyPtyAQg4t*euzSx???Sz???OySDL/TYSA_COLOURQm7t[lp{|Sv???Q{8t3m}~S|???Q3G:{lTQ}9t5T{cS~???QTH:5}3aQc:t.a}`S???Q`;tK_cS???Q<tVY`]S???QYK:V_;Q]=tS;S???S???R|RROsAEDT_EntityID_V1RowQhB:eRjzQ@hQQrh'RvPr(#Q'RRT CAPACITOROAEDT_BODYFlagGroupColor_V1PQQ?T CAPACITORP(#Q3RPthS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMERd~Rb}U56+QMb?R^{@HEA84?-RNQ<N:87DRGRR=+ SJ)]F'P&:(#T(Ceramic_materialOAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000134.x_b +BIN000000006226 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZS@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1QS&'(F)) *+2 +,-+Mb? $./+Mb??? 01gfffffMb? +2V3n4567489nQ7M:;<=4>??@A+8 <@B1n9C1gfffffMb?CB9Mb?189 Mb?BDE80CnQDO:B<FGEHI@BJKL-0FMB nQFP:0DNMOPQ0A5I-O +JRPOJMBS.+QOMJ?T-AH@IM5Q+5UnATVIHAE0LWS+HA*LXSSBIWP-WYnIK.ZSXLL0P.-XS,.;nPW Q;L:.[Y7\P:]^(#Q[=_.;`aQYK:W`b;cR\Q`<_WYd[eQbJ:KdfYgRcK bnJTWhQd;_Kbi`jQfI:TiUbkRgT fn?5K/Qi:_TfldmQUH:5l3fnRkQl9_5UoipQ3G:oqUrRnQo8_3sltQqF:,su3vRr,qnRX +-R2Qs7_,qwoxQuE:RwyqzRvR un,{O |+,{2Qw6_Ru}s~QyD:{}uRz{ynR*> -+R*2Q}5_{ywQC:*yR*n{H +{2Q4_*}QB:RQ@QQ]'RP](#Q'RRT CAPACITOR_1OAEDT_BODYFlagGroupColor_V1PQQ?T CAPACITOR_1P(#Q3RP_hS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMEP_AS???OSDL/TYSA_COLOUR3*|-+Mb?? 2 *3|R+Mb??2-{ ++Mb?S???>?{?>448QTJ+JOQP8EK+S~???Sx???St???Sp???Sm???/#T6 +Mb???6"V/+Mb??V!5Z6+gfffffMb?Z WhV+Mb??hKZ+Mb?Sj???Se???Sa???O^AEDT_EntityID_V1@HEA84?-RNQ<N:87DRGRR=+ SJ)[F'P&:(#T(Ceramic_materialOAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000150.x_b +BIN000000008435 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) $*+2 +*,-+Mb?gfffff?? >./+㥛 ?q= +ףp? 201Zd;O㥛 ?q= +ףp +2V 3n4./5406nQ5789:4;<=>?+09@A n6/BCZd;OMb?q= +ףpB.DE6㥛 ?q= +ףpC0F61Zd;OMb?gfffffFG<ADCn11AC Zd;O㥛 ?gfffffAHI0F1nQH7A9GJIKLMANOP-KIQLKRIFSTU-MKIR0?VN-NWXP0IO+OYnNZ[\PWN]A^[S+WP_]WPX`abc-^deS`P[]-[fnPOTgSd^UALT+dU,UdSeFhi+TjnS[ikQj}7TlfmnimnUTopk;Tqg+Zd;OMb?gfffff?q:rpk+Mb?gfffff?g<[k/+㥛 ?gfffff?/=g +Mb?q= +ףp?rsncbtqp9iuq+Mb?gfffff?u8bvp+㥛 ?gfffffb +wnaoruv7V\u+Zd;O㥛 ?q= +ףpVxn?.Zv\6Oyv+Zd;O㥛 ?gfffffy5oz\+㥛 ?q= +ףpo {n|ibyz4t}y+Mb?q= +ףp?t8n~rz}3Zz+Zd;OMb?q= +ףp?Zn<VO}Qz7ZxY<;h4FRZL+;4h;=<Uie-RKML<Z-=;4h~t-h`nedU^cr~-ca~`er+~c|=t+~|~ao=+a|cD]b+>En@>D|oa-"@*@?0X.M+>?4|-D XF`BnQ7DGXW]ND@.-` ^DnQ7`+`㥛 ?gfffff,EMb?gfffffE-BMb?q= +ףpP7(#Q7RQ7RROAEDT_EntityID_V1.n@V Qx7.3xQa.Q3w7Qxy7VRQbVxRPAQcZS???QdOYS???QY{7OfQe[flS???Qf|7[YjQlfTjS???QgimlS???Qm~7ij{Qho{S???Q{7omwQibwS???Qw7b{sQjrsS???Qs7rw8Qkt8S???Q87ts5S???RRRRRRROSDL/TYSA_COLOURQ`3Qv73Rn, +,2Q_Qu7,R, nˆQd ++Q2Q^,Qt7QRQn,_K --,_2Q]QQs7_R_nQW +Q2Q\_Qr7Rn_*; +_*2Q[Qq7*R*!n‚ +2QZ*Qp7RQnQ'RP(#Q'RTKBOAEDT_BODYFlagGroupColor_V1PQQmTKBP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMES???2'*+㥛 ?q= +ףp 2 *2&_+㥛 ?gfffff??2(-+#~j?RQ?2-)Q ++Zd;O#~j?RQ?2%+Mb?q= +ףpS???S???S???S???S???S???S???QG7FHRR?>@MVR+RRnQ9705HRJRR:+# SJ)'P&7(#T (Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000178.x_b +BIN000000051253 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) *+2 +J,-+ m9^o%;?x&1Կ ./+ m9^o%;?mݿ 01 m9^o%;?6^I ˿ +2V3n456789:nQ7O;<=>8?@ABCD-9=EFGn:HI m9&:?+HJK: m9^o%;?#~jԿIL:M(\^o%;?V-LdNOPQInMRIS(\&:?+R%TBUVMnSQMW(\&:?V-QbXYLZSnW[S\ m9^o%;?Fxѿ[]^_`Wn\aWb(\&:?%Cacdef\nbg\h m9&:?S㥛пgijklbnhmbn(\^o%;?mݿmWopqrhnnsht(\^o%;?Fxѿs9uvwxnntynz m9^o%;?L7A`y{|}~tnzt(\&:?(\ڿMznz(\^o%;?333333ÿ*UnV(\^o%;?+V$Rknk m9^o%;?S㥛пkVgn(\^o%;?6^I ˿2n m9&:?ؿnUG(\^o%;?)\(U'RnG9 m9^o%;?+G(\^o%;?(\ڿOn m9aÙ?333333ÿ nZ(\&:?L7A`Z`Qn m9aÙ?)\(n1 m9^o%;?ؿ~n1  m9^o%;?x&1ԿJ1nQ[;-`nJHnQ\;JJ-JnQ];+y m9&:?#~jԿxf(\^o%;?%Czx(\&:?"~j̿x6sn{(\^o%;?$CۿQn| m9&:?x&1Կ}(\&:?ؿKn~ m9^o%;?I +nK(\aÙ?)\(nKlH(\&:?S㥛пlgKnQ;lil+lnQ;v+enR(\^o%;?S㥛пQ m9&:?mݿS` m9&:?Fxѿ`[nT(\^o%;?x&1Կ?  + nU  m9&:?I + n V(\&:?I +hP nWe  m9&:?%CeanX(\&:?Sſ.nY m9&:?Sſ4 nZ}! m9^o%;?I +޿}"#$yn![ %(\&:?x&1Կ =&'w!n%\(!) m9^o%;?(\ڿ(*+,%n)]%- m9&:?(\ڿ./()n-^)0(\&:?6^I ˿012-n0_3-4 m9&:?K׿3w560n4`F0 m9^o%;?)\(F78994na4: m9^o%;?%C:b;(\aÙ?333333ÿ <=f:n;c +:>(\^o%;?#~jԿ +A?@;n>dr;A(\&:?mݿrUBCm>nAe>D(\^o%;?L7A`^EFZGAnDfHAI m9&:?$CۿHJK,DnIgGDL(\&:?I +޿G[MNqInLh_IO m9^o%;?"~j̿_PQ0[LnOiLR(\^o%;?Sſ,STOnRjOU m9^o%;?K׿yVW3RnUkRX m9&:?"~j̿mYZ6UnXlqU[(\^o%;?I +޿qY\]GmXn[mwX^(\&:?Fxѿw;_` s[n^n[a(\^o%;?"~j̿4bcx^nao ^d m9&:?6^I ˿ ef0andpag(\^o%;?ؿIhijdngq$dk m9^o%;?mݿ$lm}gnkr,gn m9^o%;?$Cۿ,op(Hknnsqkr(\&:?K׿qEstj@nnrt6nu m9&:?I +޿6rvw3rnuu9rx m9^o%;?333333ÿ9yzFunxvu(\&:?$CۿS{|rxnwjx(\^o%;?K׿jG}~qnQ};jhs~j+u~q+~-~-zn~ij+|i+-Hn…j-"q+FnQ0;DnŠ6+(\^o%;?K׿+(\&:?Fxѿ?6+(\&:?Sſ?6+ m9^o%;?Fxѿn®+ m9aÙ?)\(?n´+ m9^o%;?#~jԿn+ m9^o%;?I +޿n]+(\^o%;?Fxѿ?8n+(\^o%;?L7A`_n+(\&:?L7A`an+(\&:?Sſ/n+(\^o%;?L7A`?]n+(\&:?"~j̿7n+ m9^o%;?+nŒC+ m9^o%;?K׿xn‹+ m9&:?K׿vnt+(\^o%;?Fxѿ:n+ m9^o%;?+n+ m9&:?I +nD+ m9^o%;?I +޿nw.+ m9^o%;?(\ڿn+ m9^o%;?K׿}nŽ+ m9^o%;?ؿni+(\^o%;?"~j̿5n+ m9^o%;?%Cn +(\&:?L7A`? +n   + m9^o%;?(\ڿ n   + m9&:?#~jԿn  +(\^o%;?)\(?&n+ m9^o%;?+n+ m9^o%;?#~jԿn+(\^o%;?ؿ?+ m9^o%;?mݿ np!"#$+(\&:?I +?#%nC&$'+(\^o%;?"~j̿?3(n)$'$*+(\&:?#~jԿ?+n"'*,'-+ m9^o%;?6^I ˿,.n“/!*-0*1+ m9^o%;?Sſ02n345-1-6+ m9^o%;?%C7n89161:+(\&:?ؿ?;n™<6:=6>+ m9&:?S㥛п=?n@:>A:B+ m9^o%;?I +ACnDEF>BG>H+(\^o%;?Sſ?G+InJKBHBL+(\^o%;?#~jԿBMnžNHLH+(\aÙ?)\(?(OnPKLLQ+ m9^o%;?K׿QR+ m9aÙ?333333ÿ?SnT4QRQU+ m9^o%;?x&1ԿVnRU<RW+ m9&:?(\ڿ<Xn‚YUWUZ+(\^o%;?+#[nA\WZ]W^+(\&:?$Cۿ]T_n`abZ^cZd+ m9&:?$Cۿcenfg^d^h+(\&:?Fxѿ<injkdhldm+ m9^o%;?V-lnnopqhmhr+(\^o%;?S㥛пsnt=mrumv+ m9^o%;?$Cۿuwn&Yrvxry+ m9^o%;?SſxznT{|vyCv}+ m9&:?+C~nB#y}y+ m9^o%;?6^I ˿n‚}F}+ m9^o%;?)\(FnA{|+(\^o%;?333333ÿ?|nzx/+ m9&:?I +޿sn+(\^o%;?$Cۿ?Pnb+(\&:?I +޿?qn“+ m9^o%;?I +n—q+(\^o%;?ؿJn˜/+ m9^o%;?"~j̿/nc|,4+ m9^o%;?333333ÿ4nŸ0+(\&:?I +޿\nd+ m9^o%;?6^I ˿n¥5+(\^o%;?(\ڿNn¨Y+ m9^o%;?(\ڿYn¡u<+ m9^o%;?%Cn­+ m9&:?ؿn±+ m9^o%;?x&1Կn¾+ m9&:?"~j̿nnj!+ m9^o%;?Fxѿ!nv,+(\aÙ?333333ÿ? +n½+ m9^o%;?$Cۿnc5+ m9&:?Sſ5n0q+ m9^o%;?V-qnl +(\^o%;?I +޿Zn ++ m9^o%;?L7A`np K+(\aÙ?333333ÿ?K)nG +(\&:?I +in +(\&:?"~j̿?ln+ m9&:?Fxѿn+(\^o%;?I +޿?Xna/+(\^o%;?%Cn9/" + m9^o%;?V-"nO/Q;" +OL"+OQ+Ool-O"-DL+DPA+P-enL-Q+cnQ!;+(\^o%;?V-\+ m9^o%;?S㥛п+(\^o%;?I +gnQ;+RA+P-DA-#-PfDLnQr;PNLP (\^o%;?I +K@(\&:?#~jԿ M + m9^o%;?V-   n +N    m9&:?V- ~ +n O + m9^o%;?Sſ9 nP~  m9&:?L7A`~ y nQg;~{ ~+ Y  po+ YZ-Z -|~+|yF-y-o~p-o l+pnlQ;p n!p"#+ m9&:?L7A`"&$+(\&:?$Cۿ?#a%+(\^o%;?mݿaV&n']#%(#)+ m9aÙ?)\((<n*%)b%++(\^o%;?$CۿbR,n-])+5).+ m9&:?x&1Կ5 /n'+.++ m9&:?V-0nY..1+(\^o%;?I +?1{2+ m9&:?6^I ˿{3n2Fx12k14+(\^o%;?x&1Կk>5n6N2427+(\aÙ?)\(? 8n9474:+(\&:?ؿL;n<7:7=+ m9^o%;?ؿ>n?:=:@+ m9^o%;?L7A`AnF=@E=B+ m9&:?mݿECnCA@B@D+ m9^o%;?"~j̿EnZBDBF+ m9^o%;?S㥛пGnHDFNDI+(\^o%;?#~jԿ?N@Jn¿kFIF+(\^o%;?6^I ˿1KnLIIM+(\&:?#~jԿM@N+ m9^o%;?S㥛п@OnP\=MNM+(\^o%;?Sſ-QnRGNN+ m9aÙ?333333ÿSnT(QSM;U<VTWX+YTF+TZT-W[\XT-X[W]*(-[X^][X\9*-*_PX(+_P`P_8*Ua+_*8T-8_PFF-bU8FP+bEFY+bcEb9@-Y9-dY@+dD-@?89Y-?Ae?A@VE+A?8R+bEVa+aU-aVA-9aP]-9]\+f9=K+\[]W-gT=\W+gThTg9Z+=gK9-g=Tz|J-ziJ9|T+JizTfG+iJjTiJxk+fRJG-Rfk+lRm+knRf-n3on3kTx-nk34m-3np0q+4rm3+mr42R-r4s2rmf{L+r24 q5+ftuL 2{-Ltfl+tLvtLuw,)+lxL-xl)-xxy+)zwcxl+z){wz)0,u-cz)Q/y+zcw_|}+Q~Zy_c/-y~Qx-~Z*~yZx-Z~Q}+j+x-kjl=t+jgP+tg=-tl+tt\+t-s-jw+j +^`s- ^[v!H-`w-`^`+``+n5E'wj-' 56+'+6'5-6 kj+ 6,6+j6k- +N-@+N+ ++J+ +-@-+@Cq +nt@-tq+t3+3t--W3+W-W?-iW+-?+?i-?-?-<+<+<-<-?+/<++/<-/<++Y+/(-+(Y-++pu+---`b+`-r]+p|-b-p,u-|K&-|pH+KfH|&+&nK#u"KC`]--KCfrE'+fCKc+'CEf-'pra`+'p'mm+`m'a-q-dG+m]m+m$p-]q#+]m}.+#w}]-#Nq-wNwG-wN#6+6N+Gd-pa9+da+df--fana+e9-f+8--Fy+Ff+F|+|-Z+8-8e+86-}w-e8+$.-g+.n»g Q ;.gn³c.Q ;geg+ m9^o%;?mݿ9$+ m9&:?%C9n$"+ m9^o%;?x&1Կn$Q;+`---J-[-PkH-Pg@+Hv[+Hk\-\ n@kP@-QC;\[OP;(#Q\Q[B;QOD;@?RQ@OQ?E;=OsRQ=?QsF;?RQsQG;s7RQQ7H;RQ7QI;97RQ9QJ;8RQQ8K;RQ8QL;8SRQURPAQUSS???Q(<US???Q<N;(S7S???ROSDL/TYSA_COLOURS???S???S???S???S???S???S???S???Q[QA;O[RQ QO@; +RQO  Q?;K IO R +Q KQI>;GQR QGI QQ=;IRQQQ<;KQRQQK;;(RQKQ(:;KRQ(Q9;(RQ !Q8; "RQ #$Q7;#%R"Q#& 'Q6;&i(R%Q&)#*Qi5;)5+R(Q)i,&-Q54;k,Ji.R+Q,k5/)0QJ3;N/M51R.Q/NJ2,3QM2;2J4R1Q2M5/6Q1;5M7R4Q528R7Q95:S8???Q9;<S:???Q/;9=Q;>9?S<???Q.;;;@Q>;A;BS????Q;-;>CQAD>ESB???Q,;A;FQDGAHSE???Q+;D,IQGb,JDKSH???Q,*;bG_LQJ]_MGNSK???Q_);]J&,OQMa&PJQSN???Q&(;aM_RQPSMTSQ???Q';P&UQSVPWST???Q&;SXQV~YSZSW???Q%;V[QY}\V]SZ???Q$;Y^Q\|_Y`S]???Q#;\aQ_{\bS`???Q";_cQzd_eSb???QdyfSe???Q ;dgQxhdiSf???QhwjkSi???Q;hlQjvmhnSk???Q;joQmupjqSn???Q;mrQptsmtSq???Q;puQssvpwSt???Q;sxQvryszSw???Q;v{Qyq|v}Sz???Q;y~Q|pyS}???Q;|Qo|S???Q;QnS???Q;QmS???Q;QlqS???Q;qnQkln S???Qn;lQ jpS???Qi S???Q;QhS???Q;QgS???Q;Qf.S???QegS???QdceS???Qe ;cQcS???Q +;eQbS???Q ; Qa S???Q ;Q`S???Q;> Q_>S???Q>;Q^S???Q;>Q]S???Q;Q\S???Q;Q[S???QZS???Q;QYS???Q;GQXGS???QG;EQWES???QE;GQVS???Q;EQUS???Q;QT5S???Q;52QS02S???Q2;0QR4S???Q;4S2QQSS???QS;QPS???Q;SQOS???Q;QNS???Q;QMS???Q;;QL;S???Q;;XQK<XS???QX;<;QJYS???Q;YwXQIuwS???Qw;uQH&S???Q;&%wQG#%S???Q%;#~QFC~S???Q~;C%QES???Q; +~QD +S???Q +;AQCAS???QA; +QBS???Q;0AQA0S???Q0;VQ@VS???QV;0 Q? + S???Q;+V Q +>+ S ???Q+; +Q=" +S ???Q< S???Q ;Q;!S???Q;!. Q:,.S???Q.;,Q9/S???Q;/.Q8|S???Q;|zQ7xz !S???Qz;x3"Q 6{3#$S!???Q3;{ z%Q#5F& 'S$???Q;F#C3(Q&4AC)#*S'???QC;A&C+Q)3EC,&-S*???QC;E)C.Q,2/)0S-???Q;,/C1Q/15/2,3S0???Q/;5/34Q2035/6S3???Q3;27/8Q5/^792:S6???^7n[ ;-2Q7;^5<3=Q9.<>5?S:??? <n^ @-^2Q<;9A7BQ>-AC9DS????An E-2QA;>F<GQC,FH>ISD???!Fn… J+2QF;CKALQH+KMCNSI???jKn O+2QK;HPFQQM*PRHSSN???oPn T+2QP;MUKVQR)UWMXSS???tUn Y-2QU;RZP[QW(Z\R]SX???{Zn† ^+2QZ;W_U`Q\'_aWbS]???_n” c+2Q_;\dZeQa&df\gSb???dn h-2Qd;ai_jQf%ikalSg???inœ m+2Qi;fndoQk$npfqSl???nn¡ r-2Qn;ksitQp#sukvSq???sn¤ w+2Qs;pxnyQu"xzp{Sv???xn§| }-|2Qx;u~sQz!|~uS{???|~n¬e +e2Q~;|zxQ ezS???en|? -|2Q;e~QS???ne -e2Q;QS???n +2Q;QS???n -2Q;QS???n¿ -+2Q;QS???n +2Q;QS???n“ +2Q;QS???n™ -2Q;QS???n +2Q;QS???nº{ +{2Q;Q{S???{njz +j2Q;{QjS???jn{vi +{v2Q;jQvS???vnj`t -j`2Q;vQ`S???`nv_ +v2Q;`QS???n` +`2Q;QS???n +2Q;QS???n±, +,2Q;Q,S???, +n +-2Q;,QS??? n, -,2Q;Q S???nŠ -2Q;Q S???n¶s -s2Q;Q sS???sn–or +o2Q;sQ +oS???onscn -sc2Q;oQ cS???cnob +o2Q;cQS???nch -ch2Q;QhS???hn*g +*2Q;hQ*S???*nh~ -h2Q;* S???Q; +  R Q + Q 'R P(#Q' RT HEAT_SINKOAEDT_BODYFlagGroupColor_V1P QQ +T HEAT_SINKP(#QRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAME2%*r+(\^o%;?"~j̿?? 2 *2r$+ m9^o%;?(\ڿ2&{+Kؿ^o%;?(\ؿ??2'Y+Kؿ&:?(\ؿ??2Y(+ m9^o%;?K׿2)Y+(\^o%;?Fxѿ??2*m+ m9^o%;?mݿ2m+}+Kؿ&:?(\ؿ??2},m+(\^o%;?$Cۿ??2-}+Kؿ^o%;?(\ؿ??2.`J+ m9aÙ?)\(2J/T+(\aÙ?)\(?2T0J+Kؿ&:?(\ؿ??21T+Kؿ^o%;?(\ؿ??22e@+ m9^o%;?+2@3+ m9^o%;?%C24@+Kؿ&:?(\ؿ??25+(\^o%;?#~jԿ??26o+(\^o%;?Sſ??27+(\^o%;?I +޿??28c+Kؿ^o%;?(\ؿ??29+(\^o%;?I +??2:w+Kؿ^o%;?(\ؿ??2w;+Kؿ^o%;?(\ؿ??2<w+Kؿ^o%;?(\ؿ??2=+Kؿ&:?(\ؿ??2>j+Kؿ^o%;?(\ؿ??2?v+ m9^o%;?6^I ˿2@c+(\^o%;?L7A`??2cA+ m9aÙ?333333ÿ??2BcE+Kؿ^o%;?(\ؿ??2ECh+ m9^o%;?S㥛п2hDE;+(\^o%;?ؿ??2;E^hO+KؿaÙ?(\ؿ??2OF;+Kؿ&:?(\ؿ??2GO+ m9^o%;?V-2H|-+Kؿ&:?(\ؿ??2-I ++Kؿ&:?(\ؿ??2#h^r+(\aÙ?333333ÿ??2^"+Kؿ^o%;?(\ؿ??2!s^+Kؿ&:?(\ؿ??RRRRRRRRRRRRRRRRRRRRRRRRRRR|D#d+DBd+B-BDR8C+RRyRtRoRjReR`R[RVRQRLRGRBR=R8TR4SR1RR.QR+PR(OR%NR"MRLRKRJRIRHRFR ER DRCRBRAR@R?R>R=R<R;R:R9R8R7R6R5R4R3R2R1R0R/R.R-R,R+R*R(R'R&R%R$R#R"R!R RRRRRRRRRR~R{RxRuRrRoRl Rg Rc RaR^R[RXRURRRORLRIRFRCR@R=S6???S3???S0???S-???S*???S'???S$???S!???S???S???S???S???S???S???S ???S ???S???S???OAEDT_EntityID_V1vHs^!+}Pj-}|_Z-|}0-q| u+0w _ nQV;0ePQeU; QPW;_]RQ]X;[P RQY;`]!R QZ;"R!R"QT;e#RQS;y$R#QyR;97%R$Q7Q;F=y&R%Q=P;977'R&R'qp5-utf0|-pZq30-Zp94-iTzZ4p+R)RRHfc-(H$np$g-Q(c;Jl)QJb;Ho(*Qld;$("+R)Q"e;}l{,R+Q{f;y"-R,R-Qoa;,*J.R*Q*`;(.o/R.Q._;*0R/Q^;.1R0R1,-(-++,+Q;fc<2Qc;a3Q<;4R2YQ;<5R4XQ;6R5WQ;7R6UR7VQ;ec8R3ZQ;9R8[R9\Q;@s?:Qs;q};Q?; + <R:pQ ;?&=R<oQ&;  _>R=nQ_;w&u?R>mQu;s_@R?lQ;xubAR@kQb;BRAjQ;b1CRBiQ1;DRChQ;1SERDgQS;FREfQ;SGRFeQ;UTHRGdQT;RIRHcQ;VTJRIaQ;kiKRJbQi;gLRK`RL_R;qd-+oq-Dq+RVYQ+ Y-R!Qh;  MRQ i; NRMQ j; ORNQk; PROQl;VQRPQVm;5RRQQ5n;3VvSRRQvo;65YTRSQYp;vURTQq;YVRURVQNs;LXWRQXt;QNXRWQu;ZXEYRXQEv;MZRY~QMw;GE\[RZ}Q\x;qMo\R[|Qoy;m\B]R\{QBz;ro{^R]zQ{{;B_R^yQ|;{`R_xQ};aR`wQ~;bRavQ;hcRbuQh;}dRctRdsR R +RGRRrR]R^RRRR>+ SJ) + 'P&;e(#T (Al-ExtrudedOeAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000422.x_b +BIN000000008437 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) $*+2 +**,+zGʿMb?zG >-.+(\aÙ?zG? 2/0(\Mb?zG +1V 2n3456780nQ69:;<7=>?@4A+8;3BCn01D (\aÙ?zGD0EC0zGʿMb?HzGѿE FGHIDnC/8JDzGʿaÙ?zGJ.KLC(\Mb?HzGѿKMNI/JnL-BOJ(\aÙ?HzGѿBPQ8HLnO,IRLzGʿMb?zGI STEKOnR+HOzGʿaÙ?HzGѿHUVBERnQU9HPFWVXG3HYZ[-X3\GX]VE^_`-3XV]8T>+Yab[8VZ+ZcnYdef[aYQHgh^+aYiQa[bBA-j+gkN^B[h-hln[e_m^kg`HG_+k^n`k^NEopq+_rn^hpsQr~9_tluvp un`_wxs<_y.+zGʿMb?HzGѿ?y;z{s+zGʿMb?zG.=es +(\Mb?HzGѿ?e|njZh.Q||9e}cl~jABNeg+jA@jQ-b-j@K+Nk`gKjeo-oqK`p-o/-qoE]w-qI?z-]X3GIqw+w +n]pzQ9wuzn?wy9w{+zGʿMb?HzGѿ8d+zGʿaÙ?zG{:4y+(\Mb?zG?4n7-{Qx942-nQ4d Qy9-dnb-ZQz9dcbaQY>d+>=T78bdY-="7*T=?>I3]-?=7T/z+/@K nQ9/M@A/74?-P9(#QM9KSRQS9IFMRQF9EUSRROAEDT_EntityID_V1*!n\= ++\1Qq9*\n*X +*1 1 *Qr9\ni\ +i\12(\,+zGʿMb?HzGѿ??2'i+Gz׿aÙ?Qۿ??2,) ++Gz׿Mb?Qۿ??nn ,-n1Qv92n n…ik +i1Qu9ninna +n12%n+(\Mb?HzGѿ??2&+(\Mb?zG?Qt9iQ]iQs9RQ\RPAQ[\S???QZ*S???S???OSDL/TYSA_COLOURQ^nS???Q_S???Q`2S???Q2w9Qa4S???Qb-S???QcdS???QdZc}S???Qc{9Z|Q}ee|S???Qfhl}tS???Ql}9h|rQtg_rS???QhputS???Qu9prQiwS???QjzS???Q9z:Qk:S???:n€zQ:96S???R7m+(\Mb?zG?m6hx+(\aÙ?HzGѿ?x5p5m+(\Mb?HzGѿ?54fx+zGʿMb?zG?f3Z5+zGʿaÙ?HzGѿRRRRRRRRQp9RQnQ'RP(#Q'RTCPUOAEDT_BODYFlagGroupColor_V1PQQmTCPUP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMERRRRR~RvQP9B;URWQ;986PRRR<+# SJ)'P&9(#T (Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' +$begin 'x_b' +Design_0.setup/NativeGeometryFiles/0000450.x_b +BIN000000008459 +**ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** +**PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** +**PART1; +MC=unknown; +MC_MODEL=unknown; +MC_ID=unknown; +OS=unknown; +OS_RELEASE=unknown; +FRU=sdl_parasolid_customer_support; +APPL=Electronics Desktop; +SITE=unknown; +USER=unknown; +FORMAT=binary; +GUISE=transmit; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; +DATE=unknown; +**PART2; +SCH=SCH_3601185_36001; +USFLD_SIZE=0; +**PART3; +**END_OF_HEADER***************************************************************** +B3: TRANSMIT FILE created by modeller version 3601185SCH_3601185_36001_13006PART_XMT_BLOCK Part list n_entriesdindex_map_offsetd index_mapRschema_embedding_mapRmesh_offset_dataentries $CCCIlatticeCCCImeshIpolylineCCCCCCCDIownerCCCIboundary_latticeCCCI boundary_meshIboundary_polylineCCCAindex_map_offsetdA index_mapRAnode_id_index_mapRAschema_embedding_mapRAchild Alowest_node_iddAmesh_offset_dataZ@@:0yE>  +   @@:0yE>QF CI list_typeuI +notransmitlCCCDCCDI finger_indexdI finger_blockCZ  CCCCCCIframeCAowner ZVnJCIindex_map_offsetdCCZQQPCCCCCDI legal_ownerslCZ !DS@@O!SDL/TYSA_DENSITYP"#(#TUNIT=mmO#AEDT_EntityName_V1P$%(#S{Gz?O%AEDT_ExtentScale_V1Q&'(F)) $*+2 +*,-+?? >./+? 201 +2V 3n456789:nQ7;<=>8?@A4B-9=CDEn:0F1Mb?F/GH:Mb?11D: Mb?DIJ9G1nQI;D=KLJMNODPQR-GK4DSFnQK;GITU4VWBG8A+S T@G0XnQT;SKYZ@?[8S\]^-0 Y_S` nX,SEaE+9XMb?a-bXHbcN`anH.`aF`de0bHnQd;`Ycfeg^C`Ohi-g\j^g\eSikl+Cge\9B5O-OMJm9ehP+hnnO]Qoipql`^km-pq,qpribms-lpirS[t-k un^vtwmMON`qs+MJxNMmJbRyz+s<nm./Q<;s{|7}.|nzts /=s~ +q= +ףpͿ?~<6/+?nAyv~6;~+Mb?:56+Mb?5nB]9v+Mb??vnWk8]+?]n\5h7yo+ynNQo6h+?5Qwo+ףp= +Mb??QnPhyw4k+3tw+t +n[k.Q;tu|[?A@0ltr+?"A*A?8[G_+rplq0z.-zR_br.q+RzDNyW-_z0A[-_RGWv-WVP4Dv+VWPVBW9JQ+BV4PC5\+\gC^@]+nj*V +j*2Qr;jnxg +x2*!n’? -+22&+gfffffMb?333333ÿ?? 2 *2%+?2'x+??xn‘jM +j22(j-+??2-)* ++Qt;x n,x +,x2Qu;,np +-2Qv;,3P;(#Q_,Q3w;RQ`3Qx;53RQa5Qy;]nRQb]Qnz;hRQchnQ{;QnRQdQQ|;yRQeyQ};RQfQ~;vuRQgvQu;kRQhkuRPAQitS???Qj.|{S???Q|;.<Q{ks<S???S???ROSDL/TYSA_COLOURS???S???S???S???S???S???S???S???Q^S???Q]xS???Q\jS???Qs;jQ[S???QZ*S???Qq;*S???Qp;RQnQ'RP(#Q'RTALPHA_MAIN_PCBOAEDT_BODYFlagGroupColor_V1PQQmTALPHA_MAIN_PCBP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMEROAEDT_EntityID_V1RRRRR}QY;0TdQc;bdRfRRRZRUQ=;97IRLRR>+# SJ){c'P&;(#T (Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' +$end 'Design_0.setup/NativeGeometryFiles' +$end 'AllReferencedFilesForProject' +$begin 'ProjectPreview' + IsEncrypted=false + Thumbnail64='/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\ +BAQICAQECAQEBAgICAgICAgICAQICAgICAgICAgL/2wBDAQEBAQEBAQEBAQECAQEBAgICAgICAgICAg\ +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgL/wAARCABgAGADASIAAhEBAxEB/\ +8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR\ +BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUp\ +TVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5us\ +LDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAA\ +AECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB\ +CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ\ +3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4u\ +Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiivzA/b5/ay+O3wg+Kf7Pn7N/wL+EPxA8T/\ +wDDQHw//aB+J3xi+P3wnt/B3j/4p/sofAn9nvxH+zz4e+IPxT+Gn7N3jC0P/DRnxAm/4aC0iz0bSdLX\ +xFrGlaj9m1ux+F/xg+xy/DrXQD7f+Nfx3+Gf7PnhXT/FvxN1TxBBba54gtfCfhXw14G8AfEL4vfEzx5\ +4qutO1XXT4Z+G3wg+EXhbXfFfxL8QW/hbw94o1y+stA0XUbnTvD3g7W/EN/HbaJouq39n8AfDT/grF8\ +Pbnxp+0L4a/au+Bfxg/YL8N/Av4waL8JG+Kn7RV/8ADPXfg0uo6n8Avgf8cbqP4zfHb4E+OfF3w9/Zk\ +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' + $begin 'DesignInfo' + DesignName='IcepakDesign1' + Notes='' + Factory='Icepak' + IsSolved=false + 'Nominal Setups'[1: 'Setup1'] + 'Nominal Setup Types'[1: ''] + 'Optimetrics Setups'[0:] + 'Optimetrics Experiment Types'[0:] + Image64='/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\ +BAQICAQECAQEBAgICAgICAgICAQICAgICAgICAgL/2wBDAQEBAQEBAQEBAQECAQEBAgICAgICAgICAg\ +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgL/wAARCADIAMgDASIAAhEBAxEB/\ +8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR\ +BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUp\ +TVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5us\ +LDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAA\ +AECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB\ +CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ\ +3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4u\ +Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigAooooAKKK8A+On7UfwJ/Zw/wCEWsvix\ +45/s7xb4+/tv/hWnwp8H+GfGPxX+O3xZ/4RX+yJfGX/AAp39n/4T+Htb8bfF7+wdM1zTdS8Q/8ACM6B\ +qv8AYGjvLres/YdItrm9iAPf6K/GH9rvxz/wUVuvhT4T+KI+JPh/9g/wt4g/af8A2IvhHoXw1+E+h/C\ +/4/8A7Ss/hX9pb9tD4Bfs+6/rfxh+Lnxf8E+Ifhv4E8QQfC743+KkvfAXhDwX41ttF8b/AA/0bW9K+O\ +fjDwpPqXhnUfp//hpD42fsyf6P+3do/wAP7/4ZP+50z9sf9nDwR8XYPhZp11F/xONdu/2nPgVqEfi/U\ +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\ +' + $end 'DesignInfo' +$end 'ProjectPreview' diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 2f33454b3760..0eb2da4f4e3a 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -14,16 +14,31 @@ from tests import TESTS_UNIT_PATH import os -def load_json(): +def config_file_load(): + config_file = os.path.join(TESTS_UNIT_PATH, 'extensions','graphics_card.json') + with open(config_file, 'r') as file: + data = json.load(file) + return data - json_file = os.path.join(TESTS_UNIT_PATH, 'extensions','graphics_card.json') - with open(json_file, 'r') as file: +def mapping_load(): + mapping_file = os.path.join(TESTS_UNIT_PATH, 'extensions','mapping.json') + with open(mapping_file, 'r') as file: data = json.load(file) return data @pytest.fixture def patched_loader(): - with patch.object(IcepakModelReviewer, "get_project_data", side_effect=load_json) as mock_loader: + with patch.object(IcepakModelReviewer, "get_project_data", side_effect=config_file_load) as mock_loader: + yield mock_loader + +@pytest.fixture +def patched_object_id(): + with patch.object(IcepakModelReviewer, "object_id_mapping", side_effect=mapping_load) as mock_loader: + yield mock_loader + +@pytest.fixture +def patched_import_data_to_project(): + with patch.object(IcepakModelReviewer, "import_data_to_project", return_value = None) as mock_loader: yield mock_loader def test_icepak_model_reviewer(mock_icepak_app): @@ -49,19 +64,42 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] + assert boundary_table.tree.column(5)['id'] == 'Value 1' assert boundary_table.tree.item(row1)['values'][5] == '4W' assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' assert boundary_table.tree.item(row3)['values'][5] == '1W' + materials_table = extension.root.materials_tab.winfo_children()[0] + assert len(materials_table.tree.get_children()) == 4 + row1 = materials_table.tree.get_children()[0] + row2 = materials_table.tree.get_children()[1] + row3 = materials_table.tree.get_children()[2] + row4 = materials_table.tree.get_children()[3] + assert materials_table.tree.item(row1)['values'][3] == 152 + assert materials_table.tree.item(row2)['values'][4] == '1.1614' + assert materials_table.tree.item(row3)['values'][5] == 2 + assert materials_table.tree.item(row4)['values'][6] == 0 + model_table = extension.root.models_tab.winfo_children()[0] + assert len(model_table.tree.get_children()) == 11 + assert model_table.tree.item(row1)['values'][2] == 'air' + assert model_table.tree.item(row2)['values'][3] == 'Soft Rubber-Gray-surface' + assert model_table.tree.item(row3)['values'][4] == 'True' + assert model_table.tree.item(row3)['values'][5] == 'Model' -def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loader): +def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loader, + patched_import_data_to_project, patched_object_id): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - boundary_table.tree.set(row1)['values'][5] ='2W' - boundary_table.tree.set(row2)['values'][5] ='2w_per_m3' - boundary_table.tree.set(row3)['values'][5] ='1.5W' + boundary_table.tree.set(row1, column='Value 1', value='2W') + boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') + boundary_table.tree.set(row3, column='Value 1', value='1.5W') extension.update_button.invoke() + data = extension.root.bc_table.get_modified_data() + assert extension.combined_data['boundaries']['CPU']['Total Power'] == '2W' + assert extension.combined_data['boundaries']['Memory']['Power Density'] == '2w_per_m3' + assert extension.combined_data['boundaries']['Source1']['Total Power'] == '1.5W' + From 28502033940ace296c991570c1e584a7f37f4d80 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Wed, 10 Sep 2025 11:55:22 +0200 Subject: [PATCH 07/50] fixed issues while writing system test --- .../icepak/icepak_model_reviewer.py | 26 ++++++++----------- .../configuration_data_processing.py | 8 +++--- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 474228a00903..4757c807351e 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -134,8 +134,6 @@ def set_multi_select_options(self, header, options): self.multi_select_options[header] = options def add_row(self, row_data): - print("adding row") - print(row_data) if len(row_data) != len(self.headers) - 1: raise ValueError("Row data must match the number of non-checkbox columns") @@ -264,6 +262,7 @@ def __init__(self, withdraw: bool = False): add_custom_content=False, ) + self.differences = None self.combined_data = None self.add_extension_content() @@ -299,11 +298,12 @@ def get_project_data(self): ) ipk = Icepak() data = export_config_file(ipk) + ipk.logger.info("Loading project details into Table") if "PYTEST_CURRENT_TEST" not in os.environ: desktop.release_desktop(close_projects=False, close_on_exit=False) return data - def import_data_to_project(self, combined_data): + def import_data_to_project(self, combined_data, differences): desktop = Desktop( new_desktop=False, version=version, @@ -312,6 +312,9 @@ def import_data_to_project(self, combined_data): student_version=is_student(), ) ipk = Icepak() + ipk.logger.info("Updating the project based on modified table data") + ipk.logger.info("Following modifications are made in the table") + ipk.logger.info(differences) import_config_file(ipk, combined_data) if "PYTEST_CURRENT_TEST" not in os.environ: desktop.release_desktop(False, False) @@ -331,8 +334,6 @@ def object_id_mapping(self): return mapping def load_project(self): - print("Loading project...") - print("config_file_exported") data = self.get_project_data() self.root.json_data = data @@ -345,24 +346,19 @@ def load_project(self): self.root.model_table = add_table_to_tab(self.root.models_tab, table_data) def update_project(self): - print("Updating project...") obj_mapping = self.object_id_mapping() bc_data = self.root.bc_table.get_modified_data() bc_data = expand_list(remove_icon_from_cells(bc_data)) - differences, new_bc_data = compare_and_update_boundary_data(self.root.json_data, bc_data, obj_mapping) - print(differences) + bc_differences, new_bc_data = compare_and_update_boundary_data(self.root.json_data, bc_data, obj_mapping) mat_data = self.root.mat_table.get_modified_data() mat_data = expand_list(remove_icon_from_cells(mat_data)) - differences, new_mat_data = compare_and_update_material_data(self.root.json_data, mat_data) - print(differences) + mat_differences, new_mat_data = compare_and_update_material_data(self.root.json_data, mat_data) model_data = self.root.model_table.get_modified_data() model_data = expand_list(remove_icon_from_cells(model_data)) - differences, new_model_data = compare_and_update_model_data(self.root.json_data, model_data) - print(differences) + model_differences, new_model_data = compare_and_update_model_data(self.root.json_data, model_data) self.combined_data = {**new_model_data, **new_mat_data, **new_bc_data} - self.import_data_to_project(self.combined_data) - - + self.differences = bc_differences + mat_differences + model_differences + self.import_data_to_project(self.combined_data, self.differences) # === Main Application === diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index d34cb2ba34dd..f9a7b2f51802 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -349,14 +349,14 @@ def compare_and_update_model_data(original_data, modified_object_data): differences.append( f"{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' to '{solve_inside_bool}'" ) - updated_data["objects"][obj_name]["SolveInside"] = solve_inside_bool + updated_data["objects"][obj_name]["SolveInside"] = str(solve_inside_bool) modified_objects.add(obj_name) if original_obj.get("Model", "") != modelling_bool: differences.append( f"{obj_name}: Modeling changed from '{original_obj.get('Model', '')}' to '{modelling_bool}'" ) - updated_data["objects"][obj_name]["Model"] = modelling_bool + updated_data["objects"][obj_name]["Model"] = str(modelling_bool) updated_data["objects"][obj_name]["SurfaceMaterial"] = None modified_objects.add(obj_name) @@ -432,9 +432,9 @@ def compare_and_update_material_data(original_data, modified_object_data): if original_obj.get("viscosity", "") != viscosity: differences.append( - f"{mat_name}: diffusivity changed from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'" + f"{mat_name}: viscosity changed from '{original_obj.get('diffusivity', '')}' to '{diffusivity}'" ) - updated_data["materials"][mat_name]["viscosity"] = diffusivity + updated_data["materials"][mat_name]["viscosity"] = viscosity modified_materials.add(mat_name) modified_data = {"materials": {}} From 8875539200d4d78034efe462fc9a07ca3699bfc8 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 13 Oct 2025 16:34:29 +0200 Subject: [PATCH 08/50] removed print statements and also added theme button and relevent themes --- .../extensions/icepak/icepak_model_reviewer.py | 15 ++++++++++----- .../extensions/icepak/model_reviewer/backend.py | 5 ++--- .../configuration_data_processing.py | 7 +------ src/ansys/aedt/core/extensions/misc.py | 12 ++++++++++++ 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 4757c807351e..5e7e08347f26 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -24,6 +24,7 @@ theme = ExtensionTheme() EXTENSION_TITLE = "Icepak Model Reviewer" + def flatten_list(mixed_list): flat_list = [] for row in mixed_list: @@ -111,14 +112,14 @@ def add_table_to_tab(tab, table_data): return table -class Table(tk.Frame): +class Table(ttk.Frame): def __init__(self, parent, headers, types, read_only_data): - super().__init__(parent) + super().__init__(parent, style="PyAEDT.TFrame") self.headers = ["✔"] + headers self.types = ["checkbox"] + types self.read_only_data = [set(r) for r in read_only_data] #style.configure("Treeview", font=theme.default_font) - self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse") + self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse", style="PyAEDT.Treeview") for i, header in enumerate(self.headers): self.tree.heading(header, text=header) self.tree.column(header, width=50 if i == 0 else 140, anchor=tk.CENTER) @@ -257,7 +258,7 @@ def __init__(self, withdraw: bool = False): # Initialize the common extension class with the title and theme color super().__init__( EXTENSION_TITLE, - theme_color="light", + theme_color="dark", withdraw=withdraw, add_custom_content=False, ) @@ -282,12 +283,17 @@ def add_extension_content(self): self.load_button.pack(side=tk.LEFT,padx=5) self.update_button = ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton") self.update_button.pack(side=tk.LEFT, padx=5) + lower_frame = ttk.Frame(self.root, style="PyAEDT.TFrame") + lower_frame.pack(fill=tk.X, padx=10, pady=5) + self.add_toggle_theme_button(lower_frame,0,0) def check_design_type(self): """Check if the active design is an Icepak design.""" if self.aedt_application.design_type != "Icepak": raise AEDTRuntimeError("This extension can only be used with Icepak designs.") + + def get_project_data(self): desktop = Desktop( new_desktop=False, @@ -363,6 +369,5 @@ def update_project(self): # === Main Application === if __name__ == "__main__": - #main() extension = IcepakModelReviewer(withdraw=False) tk.mainloop() \ No newline at end of file diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index a1bd680f410f..b0b3582f2b70 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -18,13 +18,12 @@ def import_config_file(aedtapp, json_data): full_path = os.path.abspath("load.json") with open(full_path, 'w') as file: json.dump(json_data, file) - print(f"json file path is {full_path}") out = aedtapp.configurations.import_config(full_path) result = aedtapp.configurations.validate(out) if result: - print("sucessfully imported configuration") + aedtapp.logger.info("sucessfully imported configuration") else: - print("import has issues") + aedtapp.logger.info("import has issues") return None def get_object_id_mapping(aedtapp): diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index f9a7b2f51802..7b817bcc96e4 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -94,9 +94,6 @@ def extract_boundary_data(data): value1 = boundary_details.get("Surface Heat", "0kW_per_m2") value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing - print(f"Faces id {object_ids}") - # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] - # print(f"converted faces id {selected_objects}") selected_objects = [str(ids) for ids in object_ids] boundary_data.append( [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] @@ -262,9 +259,7 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object updated_data["boundaries"][boundary_name] = copy.deepcopy(original_data["boundaries"][boundary_name]) # Convert string values back to boolean where necessary - print("printing selected objects") - print(selected_objects) - print(object_mapping) + # Check for differences and update if isinstance(selected_objects, list): diff --git a/src/ansys/aedt/core/extensions/misc.py b/src/ansys/aedt/core/extensions/misc.py index aac5098d8ba0..30e0310fbc75 100644 --- a/src/ansys/aedt/core/extensions/misc.py +++ b/src/ansys/aedt/core/extensions/misc.py @@ -766,6 +766,18 @@ def _apply_theme(self, style, colors): foreground=[("active", "black"), ("!active", "black")], ) + style.configure("PyAEDT.Treeview", + background=colors["widget_bg"], + fieldbackground = colors["widget_bg"], + foreground=colors["text"], + font=self.default_font) + + # Treeview headings + style.configure("PyAEDT.Treeview.Heading", + background=colors["widget_bg"], + foreground=colors["text"], + font=self.default_font) + def __string_to_bool(v): # pragma: no cover """Change string to bool.""" From b94c5717bd5aaabfee9540c41bd51fb63d497acc Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 11:27:58 +0100 Subject: [PATCH 09/50] added additional unit tests --- .../configuration_data_processing.py | 2 +- .../extensions/test_icepak_model_reviewer.py | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 7b817bcc96e4..657bbaf2473f 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -277,7 +277,7 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object if set(original_obj_ids) != set(selected_object_ids): differences.append(f"{boundary_name}: {bc_name1} selected objects changed to '{selected_objects}'") # updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids - updated_data["boundaries"][boundary_name]["Objects"] = selected_objects_list + updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids modified_boundary.add(boundary_name) if original_obj.get(bc_name1, "") != value1: diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 0eb2da4f4e3a..1c5aa2f4005d 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -66,7 +66,9 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): row3 = boundary_table.tree.get_children()[2] assert boundary_table.tree.column(5)['id'] == 'Value 1' assert boundary_table.tree.item(row1)['values'][5] == '4W' + assert boundary_table.tree.item(row1)['values'][3] == 'CPU,KB,HEAT_SINK' assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' + assert boundary_table.tree.item(row2)['values'][3] == 'MEMORY1, MEMORY1_1' assert boundary_table.tree.item(row3)['values'][5] == '1W' materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 @@ -94,12 +96,32 @@ def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loade row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] boundary_table.tree.set(row1, column='Value 1', value='2W') + boundary_table.tree.set(row1, column='Selected Objects', value = 'CPU,KB') boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') boundary_table.tree.set(row3, column='Value 1', value='1.5W') extension.update_button.invoke() - data = extension.root.bc_table.get_modified_data() assert extension.combined_data['boundaries']['CPU']['Total Power'] == '2W' + assert extension.combined_data['boundaries']['CPU']['Objects'] == [422,150] assert extension.combined_data['boundaries']['Memory']['Power Density'] == '2w_per_m3' assert extension.combined_data['boundaries']['Source1']['Total Power'] == '1.5W' + material_table = extension.root.materials_tab.winfo_children()[0] + row1 = material_table.tree.get_children()[0] + row2 = material_table.tree.get_children()[1] + row3 = material_table.tree.get_children()[2] + material_table.tree.set(row1, column='Thermal Conductivity', value='150') + material_table.tree.set(row2, column='Mass Density', value='1.2') + material_table.tree.set(row3, column='Specific Heat', value='4') + extension.update_button.invoke() + assert extension.combined_data['materials']['Al-Extruded']['thermal_conductivity'] == '150' + assert extension.combined_data['materials']['air']['mass_density'] == '1.2' + assert extension.combined_data['materials']['PCB_Material']['specific_heat'] == '4' + model_table = extension.root.models_tab.winfo_children()[0] + row1 = model_table.tree.get_children()[1] + row2 = model_table.tree.get_children()[2] + model_table.tree.set(row1, column='Modeling', value='Non-Model') + model_table.tree.set(row2, column='Bulk Material', value = 'Al-Extruded') + extension.update_button.invoke() + assert extension.combined_data['objects']['MEMORY1']['Material'] == 'Al-Extruded' + assert extension.combined_data['objects']['SERIAL_PORT']['Model'] == 'False' From cecd2d488e6d6f1cf08b5e5f85870fabb256165e Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 12:11:48 +0100 Subject: [PATCH 10/50] System test case for icepak model reviewer extension --- tests/system/extensions/load.json | 1 + .../extensions/test_icepak_model_reviewer.py | 115 ++++ tests/unit/extensions/graphics_card.json | 544 ++++++++++++++++++ tests/unit/extensions/mapping.json | 1 + 4 files changed, 661 insertions(+) create mode 100644 tests/system/extensions/load.json create mode 100644 tests/system/extensions/test_icepak_model_reviewer.py create mode 100644 tests/unit/extensions/graphics_card.json create mode 100644 tests/unit/extensions/mapping.json diff --git a/tests/system/extensions/load.json b/tests/system/extensions/load.json new file mode 100644 index 000000000000..d3c5f591cb34 --- /dev/null +++ b/tests/system/extensions/load.json @@ -0,0 +1 @@ +{"objects": {}, "materials": {"Al-Extruded": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 232, "Green": 235, "Blue": 235}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "200", "mass_density": "2000", "specific_heat": "900", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Solid"}, "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Opaque"}}, "air": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Electromagnetic", "Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 230, "Green": 230, "Blue": 230, "Transparency": 0.949999988079071}}, "permittivity": "1.0006", "permeability": "1.0000004", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.0261", "mass_density": "1.1614", "specific_heat": "1005", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0.00333", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Fluid"}, "diffusivity": "2.88e-05", "molecular_mass": "0.028966", "viscosity": "2e-06", "material_refractive_index": "1.000293", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Transparent"}}, "PCB_Material": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 210, "Green": 105, "Blue": 30, "Transparency": 0.0}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.01", "mass_density": "2", "specific_heat": "2", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "1", "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0"}}, "boundaries": {"Source1": {"ID": 5, "BoundType": "Source", "IsComponent": false, "Faces": [155], "Thermal Condition": "Total Power", "Total Power": "1.5W", "Surface Heat": "0mW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}, "CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [422, 150], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "2W"}, "Memory": {"ID": 3, "BoundType": "Block", "IsComponent": false, "Objects": [62, 90], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": false, "Power Density": "2w_per_m3"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "134": "CAPACITOR_1", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py new file mode 100644 index 000000000000..2d95fc3bdbcb --- /dev/null +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import pytest +from pathlib import Path +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer + +from ansys.aedt.core.icepak import Icepak + +AEDT_FILENAME = "Graphics_Card" +CONFIG_FILE = "Modified_Data.json" +TEST_SUBFOLDER = "T45" +AEDT_FILE_PATH = Path(__file__).parent / "example_models" / TEST_SUBFOLDER / (AEDT_FILENAME + ".aedt") + +@pytest.fixture(autouse=True) +def ipk(add_app, request): + if hasattr(request, "param"): + prj_name = request.param + else: + prj_name = None + app = add_app(project_name=prj_name, application=Icepak, subfolder=TEST_SUBFOLDER) + yield app + app.close_project(app.project_name, False) + +@pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) +def test_successfull_data_loading(ipk): + """Test the successful execution of the power map creation in Icepak.""" + extension = IcepakModelReviewer(withdraw=False) + extension.load_button.invoke() + boundary_table = extension.root.boundary_tab.winfo_children()[0] + assert len(boundary_table.tree.get_children()) == 3 + row1 = boundary_table.tree.get_children()[0] + row2 = boundary_table.tree.get_children()[1] + row3 = boundary_table.tree.get_children()[2] + assert boundary_table.tree.item(row1)['values'][5] == '4W' + assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' + assert boundary_table.tree.item(row3)['values'][5] == '1W' + materials_table = extension.root.materials_tab.winfo_children()[0] + assert len(materials_table.tree.get_children()) == 4 + row1 = materials_table.tree.get_children()[0] + row2 = materials_table.tree.get_children()[1] + row3 = materials_table.tree.get_children()[2] + row4 = materials_table.tree.get_children()[3] + assert materials_table.tree.item(row1)['values'][3] == 152 + assert materials_table.tree.item(row2)['values'][4] == '1.1614' + assert materials_table.tree.item(row3)['values'][5] == 2 + assert materials_table.tree.item(row4)['values'][6] == 0 + model_table = extension.root.models_tab.winfo_children()[0] + assert len(model_table.tree.get_children()) == 11 + row1 = model_table.tree.get_children()[0] + row2 = model_table.tree.get_children()[1] + row3 = model_table.tree.get_children()[2] + assert model_table.tree.item(row1)['values'][2] == 'air' + assert model_table.tree.item(row2)['values'][3] == 'Soft Rubber-Gray-surface' + assert model_table.tree.item(row3)['values'][4] == 'True' + assert model_table.tree.item(row3)['values'][5] == 'Model' + +@pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) +def test_successfull_data_modification(ipk): + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + boundary_table = extension.root.boundary_tab.winfo_children()[0] + row1 = boundary_table.tree.get_children()[0] + row2 = boundary_table.tree.get_children()[1] + row3 = boundary_table.tree.get_children()[2] + boundary_table.tree.set(row1, column='Value 1', value='2W') + boundary_table.tree.set(row1, column='Selected Objects', value = 'CPU,KB') + boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') + boundary_table.tree.set(row3, column='Value 1', value='1.5W') + extension.update_button.invoke() + #assert ipk.boundaries[2].properties['Assignment'] == 'CPU, KB' + assert ipk.boundaries[3].properties['Power Density'] == '2w_per_m3' + assert ipk.boundaries[4].properties['Total Power'] == '1.5W' + materials_table = extension.root.materials_tab.winfo_children()[0] + row1 = materials_table.tree.get_children()[0] + row2 = materials_table.tree.get_children()[1] + row3 = materials_table.tree.get_children()[2] + materials_table.tree.set(row1, column='Thermal Conductivity', value='200') #Al-Extruded + materials_table.tree.set(row2, column='Viscosity', value='2e-06') #Air + materials_table.tree.set(row3, column='Mass Density', value='2') #PCB_Material + extension.update_button.invoke() + assert ipk.materials.material_keys['al-extruded'].thermal_conductivity.value == '200' + assert ipk.materials.material_keys['air'].viscosity.value == '2e-06' + assert ipk.materials.material_keys['pcb_material'].mass_density.value == '2' + model_table = extension.root.models_tab.winfo_children()[0] + row2 = model_table.tree.get_children()[1] #SERIAL_PORT + row3 = model_table.tree.get_children()[2] #MEMORY + # 6 Region, 34 serial port, 62 memory + model_table.tree.set(row2, column='Modeling', value="Non-Model") + model_table.tree.set(row3, column='Bulk Material', value='Al-Extruded') + extension.update_button.invoke() + assert ipk.modeler.objects[62].material_name == 'al-extruded' + assert ipk.modeler.objects[34].model == False + diff --git a/tests/unit/extensions/graphics_card.json b/tests/unit/extensions/graphics_card.json new file mode 100644 index 000000000000..28fac3e3d1bf --- /dev/null +++ b/tests/unit/extensions/graphics_card.json @@ -0,0 +1,544 @@ +{ + "general": { + "pyaedt_version": "0.18.0", + "model_units": "mm", + "design_name": "IcepakDesign1", + "date": "11/08/2025 14:59:14", + "object_mapping": { + "12": [ + "Region", + [ + 80.0, + 14.0, + -55.0 + ] + ], + "10": [ + "Region", + [ + -240.0, + 14.0, + -55.0 + ] + ], + "422": "CPU", + "150": "KB", + "178": "HEAT_SINK", + "62": "MEMORY1", + "90": "MEMORY1_1", + "155": [ + "KB", + [ + -153.6, + 1.6, + -102.0 + ] + ] + }, + "output_variables": {} + }, + "setups": { + "Setup1": { + "ID": 0, + "SetupType": 11, + "Enabled": true, + "MeshLink": { + "ImportMesh": false + }, + "Flow Regime": "Turbulent", + "Turbulent Model Eqn": "ZeroEquation", + "Include Temperature": true, + "Include Flow": true, + "Include Gravity": true, + "Include Solar": false, + "Solution Initialization - X Velocity": "0m_per_sec", + "Solution Initialization - Y Velocity": "0m_per_sec", + "Solution Initialization - Z Velocity": "0m_per_sec", + "Solution Initialization - Temperature": "AmbientTemp", + "Solution Initialization - Turbulent Kinetic Energy": "0", + "Solution Initialization - Turbulent Dissipation Rate": "0", + "Solution Initialization - Specific Dissipation Rate": "0", + "Solution Initialization - Use Model Based Flow Initialization": false, + "Convergence Criteria - Flow": "0.001", + "Convergence Criteria - Energy": "1e-07", + "Convergence Criteria - Turbulent Kinetic Energy": "1e-07", + "Convergence Criteria - Turbulent Dissipation Rate": "1e-07", + "Convergence Criteria - Specific Dissipation Rate": "0.001", + "Convergence Criteria - Discrete Ordinates": "1e-06", + "Convergence Criteria - Joule Heating": "1e-07", + "GPU Convergence Criteria - Flow": "0.001", + "GPU Convergence Criteria - Energy": "1e-05", + "GPU Convergence Criteria - Turbulent Kinetic Energy": "0.001", + "GPU Convergence Criteria - Turbulent Dissipation Rate": "0.001", + "GPU Convergence Criteria - Specific Dissipation Rate": "0.001", + "GPU Convergence Criteria - Discrete Ordinates": "1e-05", + "GPU Convergence Criteria - Joule Heating": "1e-07", + "IsEnabled": false, + "Radiation Model": "Off", + "Solar Radiation Model": "Solar Radiation Calculator", + "Solar Enable Participating Solids": false, + "Solar Radiation - Scattering Fraction": "0", + "Solar Radiation - North X": "0", + "Solar Radiation - North Y": "0", + "Solar Radiation - North Z": "0", + "Solar Radiation - Day": 1, + "Solar Radiation - Month": 1, + "Solar Radiation - Hours": 0, + "Solar Radiation - Minutes": 0, + "Solar Radiation - GMT": "0", + "Solar Radiation - Latitude": "0", + "Solar Radiation - Latitude Direction": "North", + "Solar Radiation - Longitude": "0", + "Solar Radiation - Longitude Direction": "East", + "Solar Radiation - Ground Reflectance": "0", + "Solar Radiation - Sunshine Fraction": "0", + "Under-relaxation - Pressure": "0.3", + "Under-relaxation - Momentum": "0.7", + "Under-relaxation - Temperature": "1", + "Under-relaxation - Turbulent Kinetic Energy": "0.8", + "Under-relaxation - Turbulent Dissipation Rate": "0.8", + "Under-relaxation - Specific Dissipation Rate": "0.8", + "Under-relaxation - Joule Heating": "1", + "Under-relaxation - Body Force": "1", + "Under-relaxation - Turbulent Viscosity": "1", + "Discretization Scheme - Pressure": "Standard", + "Discretization Scheme - Momentum": "First", + "Discretization Scheme - Temperature": "First", + "Secondary Gradient": false, + "Discretization Scheme - Turbulent Kinetic Energy": "First", + "Discretization Scheme - Turbulent Dissipation Rate": "First", + "Discretization Scheme - Specific Dissipation Rate": "First", + "Discretization Scheme - Discrete Ordinates": "First", + "Linear Solver Type - Pressure": "flex", + "Linear Solver Type - Momentum": "flex", + "Linear Solver Type - Temperature": "flex", + "Linear Solver Type - Turbulent Kinetic Energy": "flex", + "Linear Solver Type - Turbulent Dissipation Rate": "flex", + "Linear Solver Type - Specific Dissipation Rate": "flex", + "Linear Solver Type - Joule Heating": "F", + "Linear Solver Termination Criterion - Pressure": "0.1", + "Linear Solver Termination Criterion - Momentum": "0.1", + "Linear Solver Termination Criterion - Temperature": "0.1", + "Linear Solver Termination Criterion - Turbulent Kinetic Energy": "0.1", + "Linear Solver Termination Criterion - Turbulent Dissipation Rate": "0.1", + "Linear Solver Termination Criterion - Specific Dissipation Rate": "0.1", + "Linear Solver Termination Criterion - Joule Heating": "1e-09", + "Linear Solver Residual Reduction Tolerance - Pressure": "0.1", + "Linear Solver Residual Reduction Tolerance - Momentum": "0.1", + "Linear Solver Residual Reduction Tolerance - Temperature": "0.1", + "Linear Solver Residual Reduction Tolerance - Turbulent Kinetic Energy": "0.1", + "Linear Solver Residual Reduction Tolerance - Turbulent Dissipation Rate": "0.1", + "Linear Solver Residual Reduction Tolerance - Specific Dissipation Rate": "0.1", + "Linear Solver Residual Reduction Tolerance - Joule Heating": "1e-09", + "Maximum Cycles": "30", + "Linear Solver Stabilization - Pressure": "None", + "Linear Solver Stabilization - Temperature": "None", + "Linear Solver Stabilization - Joule Heating": "None", + "Coupled pressure-velocity formulation": false, + "Turn off auto-pairing for grid interface creation": false, + "2D Profile Interpolation Method": "Inverse Distance Weighted", + "Frozen Flow Simulation": false, + "TEC Coupling": false, + "Sequential Solve of Flow and Energy Equations": false, + "Convergence Criteria - Max Iterations": 100 + } + }, + "boundaries": { + "Grille1": { + "ID": 0, + "BoundType": "Grille", + "IsComponent": false, + "Faces": [ + 12 + ], + "Pressure Loss Type": "Coeff", + "Free Area Ratio": "0.8", + "Resistance Type": "Perforated Thin Vent", + "External Rad. Temperature": "AmbientTemp", + "External Total Pressure": "AmbientPressure", + "DimUnits": [ + "", + "" + ], + "X()": null, + "Y()": null + }, + "Opening1": { + "ID": 1, + "BoundType": "Opening", + "IsComponent": false, + "Faces": [ + 10 + ], + "Temperature": "AmbientTemp", + "External Rad. Temperature": "AmbientRadTemp", + "Inlet Type": "Velocity", + "Static Pressure": "AmbientPressure", + "X Velocity": "2m_per_sec", + "Y Velocity": "0m_per_sec", + "Z Velocity": "0m_per_sec", + "No Reverse Flow": false + }, + "CPU": { + "ID": 2, + "BoundType": "Block", + "IsComponent": false, + "Objects": [ + 422, + 150, + 178 + ], + "ParentBndID": -1, + "Block Type": "Solid", + "Use External Conditions": false, + "Use Total Power": true, + "Total Power": "4W" + }, + "Memory": { + "ID": 3, + "BoundType": "Block", + "IsComponent": false, + "Objects": [ + 62, + 90 + ], + "ParentBndID": -1, + "Block Type": "Solid", + "Use External Conditions": false, + "Use Total Power": false, + "Power Density": "5w_per_m3" + }, + "Source1": { + "ID": 5, + "BoundType": "Source", + "IsComponent": false, + "Faces": [ + 155 + ], + "Thermal Condition": "Total Power", + "Total Power": "1W", + "Surface Heat": "0mW_per_m2", + "Temperature": "AmbientTemp", + "Radiation": { + "Radiate": false + }, + "Voltage/Current - Enabled": false, + "Voltage/Current Option": "Current", + "Current": "0A", + "Voltage": "0V" + } + }, + "materials": { + "Al-Extruded": { + "CoordinateSystemType": "Cartesian", + "BulkOrSurfaceType": 1, + "PhysicsTypes": { + "set": [ + "Thermal" + ] + }, + "AttachedData": { + "MatAppearanceData": { + "property_data": "appearance_data", + "Red": 232, + "Green": 235, + "Blue": 235 + } + }, + "permittivity": "1", + "permeability": "1", + "conductivity": "0", + "dielectric_loss_tangent": "0", + "magnetic_loss_tangent": "0", + "thermal_conductivity": "152", + "mass_density": "2000", + "specific_heat": "900", + "youngs_modulus": "0", + "poissons_ratio": "0", + "thermal_expansion_coefficient": "0", + "thermal_material_type": { + "property_type": "ChoiceProperty", + "Choice": "Solid" + }, + "diffusivity": "0.8", + "molecular_mass": "0", + "viscosity": "0", + "clarity_type": { + "property_type": "ChoiceProperty", + "Choice": "Opaque" + } + }, + "air": { + "CoordinateSystemType": "Cartesian", + "BulkOrSurfaceType": 1, + "PhysicsTypes": { + "set": [ + "Electromagnetic", + "Thermal" + ] + }, + "AttachedData": { + "MatAppearanceData": { + "property_data": "appearance_data", + "Red": 230, + "Green": 230, + "Blue": 230, + "Transparency": 0.949999988079071 + } + }, + "permittivity": "1.0006", + "permeability": "1.0000004", + "conductivity": "0", + "dielectric_loss_tangent": "0", + "magnetic_loss_tangent": "0", + "thermal_conductivity": "0.0261", + "mass_density": "1.1614", + "specific_heat": "1005", + "youngs_modulus": "0", + "poissons_ratio": "0", + "thermal_expansion_coefficient": "0.00333", + "thermal_material_type": { + "property_type": "ChoiceProperty", + "Choice": "Fluid" + }, + "diffusivity": "2.88e-05", + "molecular_mass": "0.028966", + "viscosity": "1.84e-05", + "material_refractive_index": "1.000293", + "clarity_type": { + "property_type": "ChoiceProperty", + "Choice": "Transparent" + } + }, + "PCB_Material": { + "CoordinateSystemType": "Cartesian", + "BulkOrSurfaceType": 1, + "PhysicsTypes": { + "set": [ + "Thermal" + ] + }, + "AttachedData": { + "MatAppearanceData": { + "property_data": "appearance_data", + "Red": 210, + "Green": 105, + "Blue": 30, + "Transparency": 0.0 + } + }, + "permittivity": "1", + "permeability": "1", + "conductivity": "0", + "dielectric_loss_tangent": "0", + "magnetic_loss_tangent": "0", + "thermal_conductivity": "0.01", + "mass_density": "1", + "specific_heat": "2", + "youngs_modulus": "0", + "poissons_ratio": "0", + "thermal_expansion_coefficient": "1", + "diffusivity": "0.8", + "molecular_mass": "0", + "viscosity": "0" + }, + "Ceramic_material": { + "CoordinateSystemType": "Cartesian", + "BulkOrSurfaceType": 1, + "PhysicsTypes": { + "set": [ + "Thermal" + ] + }, + "AttachedData": { + "MatAppearanceData": { + "property_data": "appearance_data", + "Red": 0, + "Green": 100, + "Blue": 0, + "Transparency": 0.0 + } + }, + "ModifierData": { + "ThermalModifierData": { + "modifier_data": "thermal_modifier_data", + "all_thermal_modifiers": {} + } + }, + "permittivity": "1", + "permeability": "1", + "conductivity": "0", + "dielectric_loss_tangent": "0", + "magnetic_loss_tangent": "0", + "thermal_conductivity": "15", + "mass_density": "2500", + "specific_heat": "910", + "youngs_modulus": "0", + "poissons_ratio": "0", + "thermal_expansion_coefficient": "0", + "thermal_material_type": { + "property_type": "ChoiceProperty", + "Choice": "Solid" + }, + "diffusivity": "0.8", + "molecular_mass": "0", + "viscosity": "0" + } + }, + "objects": { + "Region": { + "SurfaceMaterial": "\"\"", + "Material": "air", + "SolveInside": true, + "Model": true, + "Group": "Model", + "Transparency": 0.0, + "Color": [ + 0, + 0, + 0 + ], + "CoordinateSystem": "Global" + }, + "SERIAL_PORT": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Al-Extruded", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "MEMORY1": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Ceramic_material", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "MEMORY1_1": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Ceramic_material", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "CAPACITOR": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Ceramic_material", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "CAPACITOR_1": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Ceramic_material", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "KB": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Al-Extruded", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "HEAT_SINK": { + "SurfaceMaterial": "\"Soft Rubber-Gray-surface\"", + "Material": "Al-Extruded", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "CPU": { + "SurfaceMaterial": "\"Steel-oxidised-surface\"", + "Material": "Al-Extruded", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "ALPHA_MAIN_PCB": { + "SurfaceMaterial": "\"Steel-oxidised-surface\"", + "Material": "Al-Extruded", + "SolveInside": true, + "Model": true, + "Group": "graphics_card_simple", + "Transparency": 0.0, + "Color": [ + 175, + 175, + 175 + ], + "CoordinateSystem": "Global" + }, + "Box1": { + "SurfaceMaterial": null, + "Material": "", + "SolveInside": false, + "Model": false, + "Group": "Model", + "Transparency": 0.0, + "Color": [ + 0, + 0, + 255 + ], + "CoordinateSystem": "Global" + } + } +} \ No newline at end of file diff --git a/tests/unit/extensions/mapping.json b/tests/unit/extensions/mapping.json new file mode 100644 index 000000000000..b23aa24c23ea --- /dev/null +++ b/tests/unit/extensions/mapping.json @@ -0,0 +1 @@ +{"Region": 6, "SERIAL_PORT": 34, "MEMORY1": 62, "MEMORY1_1": 90, "CAPACITOR": 118, "CAPACITOR_1": 134, "KB": 150, "HEAT_SINK": 178, "CPU": 422, "ALPHA_MAIN_PCB": 450, "Box1": 498, "MeshRegion1_SubRegion": 554, "MeshRegion2_SubRegion": 582} \ No newline at end of file From 058d9e2548f34ba5fbd93fdd19ef96aa9a09ef93 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:13:34 +0100 Subject: [PATCH 11/50] json file for testing icepak model reviewer extension --- tests/system/extensions/load.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/extensions/load.json b/tests/system/extensions/load.json index d3c5f591cb34..72a6a9dfd7b7 100644 --- a/tests/system/extensions/load.json +++ b/tests/system/extensions/load.json @@ -1 +1 @@ -{"objects": {}, "materials": {"Al-Extruded": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 232, "Green": 235, "Blue": 235}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "200", "mass_density": "2000", "specific_heat": "900", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Solid"}, "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Opaque"}}, "air": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Electromagnetic", "Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 230, "Green": 230, "Blue": 230, "Transparency": 0.949999988079071}}, "permittivity": "1.0006", "permeability": "1.0000004", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.0261", "mass_density": "1.1614", "specific_heat": "1005", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0.00333", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Fluid"}, "diffusivity": "2.88e-05", "molecular_mass": "0.028966", "viscosity": "2e-06", "material_refractive_index": "1.000293", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Transparent"}}, "PCB_Material": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 210, "Green": 105, "Blue": 30, "Transparency": 0.0}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.01", "mass_density": "2", "specific_heat": "2", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "1", "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0"}}, "boundaries": {"Source1": {"ID": 5, "BoundType": "Source", "IsComponent": false, "Faces": [155], "Thermal Condition": "Total Power", "Total Power": "1.5W", "Surface Heat": "0mW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}, "CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [422, 150], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "2W"}, "Memory": {"ID": 3, "BoundType": "Block", "IsComponent": false, "Objects": [62, 90], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": false, "Power Density": "2w_per_m3"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "134": "CAPACITOR_1", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file +{"objects": {"MEMORY1": {"SurfaceMaterial": "Soft Rubber-Gray-surface", "Material": "Al-Extruded", "SolveInside": true, "Model": true, "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}, "SERIAL_PORT": {"SurfaceMaterial": null, "Material": "Al-Extruded", "SolveInside": true, "Model": "False", "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}}, "materials": {"PCB_Material": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 210, "Green": 105, "Blue": 30, "Transparency": 0.0}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.01", "mass_density": "2", "specific_heat": "2", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "1", "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0"}, "Al-Extruded": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 232, "Green": 235, "Blue": 235}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "200", "mass_density": "2000", "specific_heat": "900", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Solid"}, "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Opaque"}}, "air": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Electromagnetic", "Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 230, "Green": 230, "Blue": 230, "Transparency": 0.949999988079071}}, "permittivity": "1.0006", "permeability": "1.0000004", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.0261", "mass_density": "1.1614", "specific_heat": "1005", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0.00333", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Fluid"}, "diffusivity": "2.88e-05", "molecular_mass": "0.028966", "viscosity": "2e-06", "material_refractive_index": "1.000293", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Transparent"}}}, "boundaries": {"Memory": {"ID": 3, "BoundType": "Block", "IsComponent": false, "Objects": [62, 90], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": false, "Power Density": "2w_per_m3"}, "CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [422, 150], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "2W"}, "Source1": {"ID": 5, "BoundType": "Source", "IsComponent": false, "Faces": [155], "Thermal Condition": "Total Power", "Total Power": "1.5W", "Surface Heat": "0mW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "134": "CAPACITOR_1", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file From 4dae7d3f1f294094cbb61689412a75448d63823e Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:13:56 +0100 Subject: [PATCH 12/50] selected assignment added to system test --- tests/system/extensions/test_icepak_model_reviewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 2d95fc3bdbcb..9187ae781802 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -89,7 +89,7 @@ def test_successfull_data_modification(ipk): boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') boundary_table.tree.set(row3, column='Value 1', value='1.5W') extension.update_button.invoke() - #assert ipk.boundaries[2].properties['Assignment'] == 'CPU, KB' + assert ipk.boundaries[2].properties['Assignment'] == 'CPU, KB' assert ipk.boundaries[3].properties['Power Density'] == '2w_per_m3' assert ipk.boundaries[4].properties['Total Power'] == '1.5W' materials_table = extension.root.materials_tab.winfo_children()[0] From 39dae8859ec884fcd928734f602b12fb77e9cd77 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:14:23 +0100 Subject: [PATCH 13/50] boundary update assignment to reflected changes in selected object --- src/ansys/aedt/core/generic/configurations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/aedt/core/generic/configurations.py b/src/ansys/aedt/core/generic/configurations.py index f9e2accd1cdf..597f4a4d6e58 100644 --- a/src/ansys/aedt/core/generic/configurations.py +++ b/src/ansys/aedt/core/generic/configurations.py @@ -896,6 +896,7 @@ def _update_boundaries(self, name, props): if not self.options.skip_import_if_exists: bound.props.update({k: props[k] for k in bound.props if k in props}) bound.update() + bound.update_assignment() return True bound = BoundaryObject(self._app, name, props, props["BoundType"]) if bound.props.get("Independent", None): From 8a71562a907aab3e6a27b8d8e0d3c1501c9646cf Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:23:04 +0100 Subject: [PATCH 14/50] removed unneccessary commands --- .../core/extensions/icepak/icepak_model_reviewer.py | 9 ++------- .../core/extensions/icepak/model_reviewer/backend.py | 4 ++-- .../model_reviewer/configuration_data_processing.py | 11 +++++------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 5e7e08347f26..5d7ed1b06c38 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -2,21 +2,17 @@ import os from tkinter import ttk from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file -#from model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file from ansys.aedt.core.extensions.misc import get_aedt_version from ansys.aedt.core.extensions.misc import get_port from ansys.aedt.core.extensions.misc import get_process_id from ansys.aedt.core.extensions.misc import is_student from ansys.aedt.core.extensions.misc import ExtensionCommon -from ansys.aedt.core.extensions.misc import ExtensionCommonData from ansys.aedt.core.extensions.misc import ExtensionTheme from ansys.aedt.core import * from ansys.aedt.core.internal.errors import AEDTRuntimeError from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data -#from model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ -# compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data port = get_port() version = get_aedt_version() @@ -118,7 +114,6 @@ def __init__(self, parent, headers, types, read_only_data): self.headers = ["✔"] + headers self.types = ["checkbox"] + types self.read_only_data = [set(r) for r in read_only_data] - #style.configure("Treeview", font=theme.default_font) self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse", style="PyAEDT.Treeview") for i, header in enumerate(self.headers): self.tree.heading(header, text=header) @@ -152,7 +147,7 @@ def toggle_row(self, row_id, item_index): def get_modified_data(self): return [self.tree.item(row)["values"][1: ] for row in self.tree.get_children()] - #return [row[1:] for row in self.rows_data] # exclude checkbox column + def edit_cell(self, event): region = self.tree.identify("region", event.x, event.y) @@ -367,7 +362,7 @@ def update_project(self): self.import_data_to_project(self.combined_data, self.differences) -# === Main Application === + if __name__ == "__main__": extension = IcepakModelReviewer(withdraw=False) tk.mainloop() \ No newline at end of file diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index b0b3582f2b70..f45b8dd84330 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -21,9 +21,9 @@ def import_config_file(aedtapp, json_data): out = aedtapp.configurations.import_config(full_path) result = aedtapp.configurations.validate(out) if result: - aedtapp.logger.info("sucessfully imported configuration") + aedtapp.logger.info("Sucessfully imported configuration") else: - aedtapp.logger.info("import has issues") + aedtapp.logger.info("Import has issues") return None def get_object_id_mapping(aedtapp): diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 657bbaf2473f..597d9937aab5 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -32,6 +32,7 @@ def extract_boundary_data(data): selection_dict = {} headings = ["Boundary Name", "Boundary Type", "Selected Objects", "BC Name 1", "Value 1", "BC Name 2", "Value 2"] type_list = ["text", "text", "multiple_text", "text", "text", "text", "text"] + # Convert mapping to ensure all values are names (some are lists) id_to_name = {} for obj_id, value in object_mapping.items(): @@ -46,7 +47,6 @@ def extract_boundary_data(data): for boundary_name, boundary_details in data.get("boundaries", {}).items(): cols = [1, 2, 4, 6] boundary_type = boundary_details.get("BoundType", "") - # block_type = boundary_details.get("Block Type", "") # Solid or Fluid if boundary_type == "Block": use_total_power = boundary_details.get("Use Total Power", "") use_external_conditions = boundary_details.get("Use External Conditions", "") @@ -276,7 +276,6 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object if original_obj_ids: if set(original_obj_ids) != set(selected_object_ids): differences.append(f"{boundary_name}: {bc_name1} selected objects changed to '{selected_objects}'") - # updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids modified_boundary.add(boundary_name) @@ -308,11 +307,11 @@ def compare_and_update_model_data(original_data, modified_object_data): Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - # updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + updated_data = {"objects": {}} differences = [] modified_objects = set() - # Convert object data into a lookup dictionary for easy comparison + for row in modified_object_data: obj_name, bulk_material, surface_material, solve_inside, modelling = row @@ -367,10 +366,10 @@ def compare_and_update_material_data(original_data, modified_object_data): Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - # updated_data = copy.deepcopy(original_data) # Make a copy to avoid modifying original + differences = [] updated_data = {"materials": {}} - # Convert object data into a lookup dictionary for easy comparison + modified_materials = set() for row in modified_object_data: ( From afa858dfd688642737ccdc1243b93718df4738e6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:24:51 +0000 Subject: [PATCH 15/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/icepak_model_reviewer.py | 111 +++++++++++----- .../icepak/model_reviewer/__init__.py | 23 ++++ .../icepak/model_reviewer/backend.py | 31 ++++- .../configuration_data_processing.py | 3 - src/ansys/aedt/core/extensions/misc.py | 19 +-- .../extensions/test_icepak_model_reviewer.py | 67 +++++----- .../general/test_01_configuration_files.py | 4 +- .../extensions/test_icepak_model_reviewer.py | 124 +++++++++++------- 8 files changed, 253 insertions(+), 129 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 5d7ed1b06c38..14d8be6b055b 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -1,19 +1,53 @@ -import tkinter as tk +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import os +import tkinter as tk from tkinter import ttk -from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, get_object_id_mapping, import_config_file + +from ansys.aedt.core import * +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import get_object_id_mapping +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import import_config_file +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import ( + compare_and_update_boundary_data, +) +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import ( + compare_and_update_material_data, +) +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import compare_and_update_model_data +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_boundary_data +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_material_data +from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_model_data +from ansys.aedt.core.extensions.misc import ExtensionCommon +from ansys.aedt.core.extensions.misc import ExtensionTheme from ansys.aedt.core.extensions.misc import get_aedt_version from ansys.aedt.core.extensions.misc import get_port from ansys.aedt.core.extensions.misc import get_process_id from ansys.aedt.core.extensions.misc import is_student -from ansys.aedt.core.extensions.misc import ExtensionCommon -from ansys.aedt.core.extensions.misc import ExtensionTheme -from ansys.aedt.core import * from ansys.aedt.core.internal.errors import AEDTRuntimeError -from ansys.aedt.core.extensions.icepak.model_reviewer.configuration_data_processing import extract_boundary_data, extract_material_data, extract_model_data, \ - compare_and_update_boundary_data, compare_and_update_material_data, compare_and_update_model_data - port = get_port() version = get_aedt_version() aedt_process_id = get_process_id() @@ -33,6 +67,7 @@ def flatten_list(mixed_list): flat_list.append(result) return flat_list + def expand_list(flat_list): mixed_list = [] for row in flat_list: @@ -46,54 +81,64 @@ def expand_list(flat_list): mixed_list.append(result) return mixed_list + def add_icon_to_cells(data, icon_indices, icon="🔒"): """ Adds an icon to specified cells in the data. - Parameters: + + Parameters + ---------- - data: list of list of strings (table rows) - icon_indices: list of list of ints, where each inner list contains read only column indices - icon: string icon to prepend (default '🔒') - Returns: + Returns + ------- - new_data: deep copy of data with icons added """ from copy import deepcopy + new_data = deepcopy(data) for row_idx, cols in enumerate(icon_indices): for col_idx in cols: - cell = new_data[row_idx][col_idx-1] + cell = new_data[row_idx][col_idx - 1] if isinstance(cell, str): - new_data[row_idx][col_idx-1] = f"{cell}{icon}" + new_data[row_idx][col_idx - 1] = f"{cell}{icon}" elif isinstance(cell, list): cell[-1] += icon - new_data[row_idx][col_idx-1] = cell + new_data[row_idx][col_idx - 1] = cell return new_data + def remove_icon_from_cells(data, icon="🔒"): """ Removes the icon from all cells that start with it. - Parameters: + Parameters + ---------- - data: list of list of strings - icon: the icon to remove (default '🔒') - Returns: + Returns + ------- - new_data: deep copy of data with icons removed """ from copy import deepcopy + new_data = deepcopy(data) for i, row in enumerate(new_data): for j, cell in enumerate(row): if isinstance(cell, str): - if cell.endswith(f"{icon}"): # cells can also be list in case of multiple selection - new_data[i][j] = cell[:-(len(icon))] + if cell.endswith(f"{icon}"): # cells can also be list in case of multiple selection + new_data[i][j] = cell[: -(len(icon))] if isinstance(cell, list): if cell[-1].endswith(icon): - cell[-1] = cell[-1][:-(len(icon))] + cell[-1] = cell[-1][: -(len(icon))] return new_data + def add_table_to_tab(tab, table_data): for child in tab.winfo_children(): child.destroy() @@ -114,7 +159,9 @@ def __init__(self, parent, headers, types, read_only_data): self.headers = ["✔"] + headers self.types = ["checkbox"] + types self.read_only_data = [set(r) for r in read_only_data] - self.tree = ttk.Treeview(self, columns=self.headers, show="headings", selectmode="browse", style="PyAEDT.Treeview") + self.tree = ttk.Treeview( + self, columns=self.headers, show="headings", selectmode="browse", style="PyAEDT.Treeview" + ) for i, header in enumerate(self.headers): self.tree.heading(header, text=header) self.tree.column(header, width=50 if i == 0 else 140, anchor=tk.CENTER) @@ -146,8 +193,7 @@ def toggle_row(self, row_id, item_index): self.tree.set(row_id, 0, "✅") def get_modified_data(self): - return [self.tree.item(row)["values"][1: ] for row in self.tree.get_children()] - + return [self.tree.item(row)["values"][1:] for row in self.tree.get_children()] def edit_cell(self, event): region = self.tree.identify("region", event.x, event.y) @@ -195,7 +241,6 @@ def apply_to_selected(new_value): entry.place(x=x, y=y, width=width, height=height) entry.focus_set() - def on_return(event): new_value = entry.get() apply_to_selected(new_value) @@ -206,7 +251,9 @@ def on_return(event): elif type_ == "combo": options = self.multi_select_options.get(self.headers[col], []) - combo = ttk.Combobox(self.tree, values=options, state="readonly", style="PyAEDT.TCombobox", font=theme.default_font) + combo = ttk.Combobox( + self.tree, values=options, state="readonly", style="PyAEDT.TCombobox", font=theme.default_font + ) combo.place(x=x, y=y, width=width, height=height) combo.set(value) @@ -247,7 +294,6 @@ def confirm(): self.wait_window(top) - class IcepakModelReviewer(ExtensionCommon): def __init__(self, withdraw: bool = False): # Initialize the common extension class with the title and theme color @@ -274,21 +320,23 @@ def add_extension_content(self): notebook.add(self.root.materials_tab, text="Material") self.root.models_tab = ttk.Frame(notebook, style="PyAEDT.TFrame") notebook.add(self.root.models_tab, text="Models") - self.load_button = ttk.Button(button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton") - self.load_button.pack(side=tk.LEFT,padx=5) - self.update_button = ttk.Button(button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton") + self.load_button = ttk.Button( + button_frame, text="Load Project", command=self.load_project, style="PyAEDT.TButton" + ) + self.load_button.pack(side=tk.LEFT, padx=5) + self.update_button = ttk.Button( + button_frame, text="Update Project", command=self.update_project, style="PyAEDT.TButton" + ) self.update_button.pack(side=tk.LEFT, padx=5) lower_frame = ttk.Frame(self.root, style="PyAEDT.TFrame") lower_frame.pack(fill=tk.X, padx=10, pady=5) - self.add_toggle_theme_button(lower_frame,0,0) + self.add_toggle_theme_button(lower_frame, 0, 0) def check_design_type(self): """Check if the active design is an Icepak design.""" if self.aedt_application.design_type != "Icepak": raise AEDTRuntimeError("This extension can only be used with Icepak designs.") - - def get_project_data(self): desktop = Desktop( new_desktop=False, @@ -362,7 +410,6 @@ def update_project(self): self.import_data_to_project(self.combined_data, self.differences) - if __name__ == "__main__": extension = IcepakModelReviewer(withdraw=False) - tk.mainloop() \ No newline at end of file + tk.mainloop() diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py index e69de29bb2d1..b78d8fed76c9 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index f45b8dd84330..eab14885ea48 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -1,6 +1,31 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import json import os + def export_config_file(aedtapp): aedtapp.configurations.options.export_monitor = False aedtapp.configurations.options.export_native_components = False @@ -10,13 +35,14 @@ def export_config_file(aedtapp): aedtapp.configurations.options.export_mesh_operations = False aedtapp.configurations.options.export_optimizations = False config_file = aedtapp.configurations.export_config() - with open(config_file, 'r') as file: + with open(config_file, "r") as file: data = json.load(file) return data + def import_config_file(aedtapp, json_data): full_path = os.path.abspath("load.json") - with open(full_path, 'w') as file: + with open(full_path, "w") as file: json.dump(json_data, file) out = aedtapp.configurations.import_config(full_path) result = aedtapp.configurations.validate(out) @@ -26,6 +52,7 @@ def import_config_file(aedtapp, json_data): aedtapp.logger.info("Import has issues") return None + def get_object_id_mapping(aedtapp): object_id_map = {name: aedtapp.modeler.get_obj_id(name) for name in aedtapp.modeler.object_names} return object_id_map diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 597d9937aab5..45b91d261ef6 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -260,7 +260,6 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object # Convert string values back to boolean where necessary - # Check for differences and update if isinstance(selected_objects, list): selected_object_ids = [int(i) if str(i).isdigit() else object_mapping[i] for i in selected_objects] @@ -307,7 +306,6 @@ def compare_and_update_model_data(original_data, modified_object_data): Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - updated_data = {"objects": {}} differences = [] modified_objects = set() @@ -366,7 +364,6 @@ def compare_and_update_material_data(original_data, modified_object_data): Compares modified object data with the original data and identifies differences. Also returns the updated original data with the modifications applied. """ - differences = [] updated_data = {"materials": {}} diff --git a/src/ansys/aedt/core/extensions/misc.py b/src/ansys/aedt/core/extensions/misc.py index e26736827c03..e8cb2f902da4 100644 --- a/src/ansys/aedt/core/extensions/misc.py +++ b/src/ansys/aedt/core/extensions/misc.py @@ -1038,17 +1038,18 @@ def _apply_theme(self, style, colors): foreground=[("active", "black"), ("!active", "black")], ) - style.configure("PyAEDT.Treeview", - background=colors["widget_bg"], - fieldbackground = colors["widget_bg"], - foreground=colors["text"], - font=self.default_font) + style.configure( + "PyAEDT.Treeview", + background=colors["widget_bg"], + fieldbackground=colors["widget_bg"], + foreground=colors["text"], + font=self.default_font, + ) # Treeview headings - style.configure("PyAEDT.Treeview.Heading", - background=colors["widget_bg"], - foreground=colors["text"], - font=self.default_font) + style.configure( + "PyAEDT.Treeview.Heading", background=colors["widget_bg"], foreground=colors["text"], font=self.default_font + ) def __string_to_bool(v): # pragma: no cover diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 9187ae781802..90f98b062ed2 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -22,10 +22,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import pytest from pathlib import Path -from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer +import pytest + +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer from ansys.aedt.core.icepak import Icepak AEDT_FILENAME = "Graphics_Card" @@ -33,6 +34,7 @@ TEST_SUBFOLDER = "T45" AEDT_FILE_PATH = Path(__file__).parent / "example_models" / TEST_SUBFOLDER / (AEDT_FILENAME + ".aedt") + @pytest.fixture(autouse=True) def ipk(add_app, request): if hasattr(request, "param"): @@ -43,6 +45,7 @@ def ipk(add_app, request): yield app app.close_project(app.project_name, False) + @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_data_loading(ipk): """Test the successful execution of the power map creation in Icepak.""" @@ -53,28 +56,29 @@ def test_successfull_data_loading(ipk): row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - assert boundary_table.tree.item(row1)['values'][5] == '4W' - assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' - assert boundary_table.tree.item(row3)['values'][5] == '1W' + assert boundary_table.tree.item(row1)["values"][5] == "4W" + assert boundary_table.tree.item(row2)["values"][5] == "5w_per_m3" + assert boundary_table.tree.item(row3)["values"][5] == "1W" materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 row1 = materials_table.tree.get_children()[0] row2 = materials_table.tree.get_children()[1] row3 = materials_table.tree.get_children()[2] row4 = materials_table.tree.get_children()[3] - assert materials_table.tree.item(row1)['values'][3] == 152 - assert materials_table.tree.item(row2)['values'][4] == '1.1614' - assert materials_table.tree.item(row3)['values'][5] == 2 - assert materials_table.tree.item(row4)['values'][6] == 0 + assert materials_table.tree.item(row1)["values"][3] == 152 + assert materials_table.tree.item(row2)["values"][4] == "1.1614" + assert materials_table.tree.item(row3)["values"][5] == 2 + assert materials_table.tree.item(row4)["values"][6] == 0 model_table = extension.root.models_tab.winfo_children()[0] assert len(model_table.tree.get_children()) == 11 row1 = model_table.tree.get_children()[0] row2 = model_table.tree.get_children()[1] row3 = model_table.tree.get_children()[2] - assert model_table.tree.item(row1)['values'][2] == 'air' - assert model_table.tree.item(row2)['values'][3] == 'Soft Rubber-Gray-surface' - assert model_table.tree.item(row3)['values'][4] == 'True' - assert model_table.tree.item(row3)['values'][5] == 'Model' + assert model_table.tree.item(row1)["values"][2] == "air" + assert model_table.tree.item(row2)["values"][3] == "Soft Rubber-Gray-surface" + assert model_table.tree.item(row3)["values"][4] == "True" + assert model_table.tree.item(row3)["values"][5] == "Model" + @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_data_modification(ipk): @@ -84,32 +88,31 @@ def test_successfull_data_modification(ipk): row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - boundary_table.tree.set(row1, column='Value 1', value='2W') - boundary_table.tree.set(row1, column='Selected Objects', value = 'CPU,KB') - boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') - boundary_table.tree.set(row3, column='Value 1', value='1.5W') + boundary_table.tree.set(row1, column="Value 1", value="2W") + boundary_table.tree.set(row1, column="Selected Objects", value="CPU,KB") + boundary_table.tree.set(row2, column="Value 1", value="2w_per_m3") + boundary_table.tree.set(row3, column="Value 1", value="1.5W") extension.update_button.invoke() - assert ipk.boundaries[2].properties['Assignment'] == 'CPU, KB' - assert ipk.boundaries[3].properties['Power Density'] == '2w_per_m3' - assert ipk.boundaries[4].properties['Total Power'] == '1.5W' + assert ipk.boundaries[2].properties["Assignment"] == "CPU, KB" + assert ipk.boundaries[3].properties["Power Density"] == "2w_per_m3" + assert ipk.boundaries[4].properties["Total Power"] == "1.5W" materials_table = extension.root.materials_tab.winfo_children()[0] row1 = materials_table.tree.get_children()[0] row2 = materials_table.tree.get_children()[1] row3 = materials_table.tree.get_children()[2] - materials_table.tree.set(row1, column='Thermal Conductivity', value='200') #Al-Extruded - materials_table.tree.set(row2, column='Viscosity', value='2e-06') #Air - materials_table.tree.set(row3, column='Mass Density', value='2') #PCB_Material + materials_table.tree.set(row1, column="Thermal Conductivity", value="200") # Al-Extruded + materials_table.tree.set(row2, column="Viscosity", value="2e-06") # Air + materials_table.tree.set(row3, column="Mass Density", value="2") # PCB_Material extension.update_button.invoke() - assert ipk.materials.material_keys['al-extruded'].thermal_conductivity.value == '200' - assert ipk.materials.material_keys['air'].viscosity.value == '2e-06' - assert ipk.materials.material_keys['pcb_material'].mass_density.value == '2' + assert ipk.materials.material_keys["al-extruded"].thermal_conductivity.value == "200" + assert ipk.materials.material_keys["air"].viscosity.value == "2e-06" + assert ipk.materials.material_keys["pcb_material"].mass_density.value == "2" model_table = extension.root.models_tab.winfo_children()[0] - row2 = model_table.tree.get_children()[1] #SERIAL_PORT - row3 = model_table.tree.get_children()[2] #MEMORY + row2 = model_table.tree.get_children()[1] # SERIAL_PORT + row3 = model_table.tree.get_children()[2] # MEMORY # 6 Region, 34 serial port, 62 memory - model_table.tree.set(row2, column='Modeling', value="Non-Model") - model_table.tree.set(row3, column='Bulk Material', value='Al-Extruded') + model_table.tree.set(row2, column="Modeling", value="Non-Model") + model_table.tree.set(row3, column="Bulk Material", value="Al-Extruded") extension.update_button.invoke() - assert ipk.modeler.objects[62].material_name == 'al-extruded' + assert ipk.modeler.objects[62].material_name == "al-extruded" assert ipk.modeler.objects[34].model == False - diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index 6bf15645fbd3..e30a1cdd8fcf 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -26,12 +26,12 @@ import os import time +import pytest + from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d -import pytest - from tests import TESTS_GENERAL_PATH from tests.conftest import config diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 1c5aa2f4005d..ba9a897a122b 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -1,46 +1,70 @@ -from textwrap import dedent -from tkinter import TclError +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import json +import os from unittest.mock import patch import pytest from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer - - -import pytest -from unittest.mock import patch -import json from tests import TESTS_UNIT_PATH -import os + def config_file_load(): - config_file = os.path.join(TESTS_UNIT_PATH, 'extensions','graphics_card.json') - with open(config_file, 'r') as file: + config_file = os.path.join(TESTS_UNIT_PATH, "extensions", "graphics_card.json") + with open(config_file, "r") as file: data = json.load(file) return data + def mapping_load(): - mapping_file = os.path.join(TESTS_UNIT_PATH, 'extensions','mapping.json') - with open(mapping_file, 'r') as file: + mapping_file = os.path.join(TESTS_UNIT_PATH, "extensions", "mapping.json") + with open(mapping_file, "r") as file: data = json.load(file) return data + @pytest.fixture def patched_loader(): with patch.object(IcepakModelReviewer, "get_project_data", side_effect=config_file_load) as mock_loader: yield mock_loader + @pytest.fixture def patched_object_id(): with patch.object(IcepakModelReviewer, "object_id_mapping", side_effect=mapping_load) as mock_loader: yield mock_loader + @pytest.fixture def patched_import_data_to_project(): - with patch.object(IcepakModelReviewer, "import_data_to_project", return_value = None) as mock_loader: + with patch.object(IcepakModelReviewer, "import_data_to_project", return_value=None) as mock_loader: yield mock_loader + def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" extension = IcepakModelReviewer(withdraw=True) @@ -50,6 +74,7 @@ def test_icepak_model_reviewer(mock_icepak_app): extension.root.destroy() + def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() @@ -57,6 +82,7 @@ def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): assert boundary_table.tree is not None assert len(boundary_table.tree.get_children()) == 3 + def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() @@ -64,64 +90,64 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - assert boundary_table.tree.column(5)['id'] == 'Value 1' - assert boundary_table.tree.item(row1)['values'][5] == '4W' - assert boundary_table.tree.item(row1)['values'][3] == 'CPU,KB,HEAT_SINK' - assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' - assert boundary_table.tree.item(row2)['values'][3] == 'MEMORY1, MEMORY1_1' - assert boundary_table.tree.item(row3)['values'][5] == '1W' + assert boundary_table.tree.column(5)["id"] == "Value 1" + assert boundary_table.tree.item(row1)["values"][5] == "4W" + assert boundary_table.tree.item(row1)["values"][3] == "CPU,KB,HEAT_SINK" + assert boundary_table.tree.item(row2)["values"][5] == "5w_per_m3" + assert boundary_table.tree.item(row2)["values"][3] == "MEMORY1, MEMORY1_1" + assert boundary_table.tree.item(row3)["values"][5] == "1W" materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 row1 = materials_table.tree.get_children()[0] row2 = materials_table.tree.get_children()[1] row3 = materials_table.tree.get_children()[2] row4 = materials_table.tree.get_children()[3] - assert materials_table.tree.item(row1)['values'][3] == 152 - assert materials_table.tree.item(row2)['values'][4] == '1.1614' - assert materials_table.tree.item(row3)['values'][5] == 2 - assert materials_table.tree.item(row4)['values'][6] == 0 + assert materials_table.tree.item(row1)["values"][3] == 152 + assert materials_table.tree.item(row2)["values"][4] == "1.1614" + assert materials_table.tree.item(row3)["values"][5] == 2 + assert materials_table.tree.item(row4)["values"][6] == 0 model_table = extension.root.models_tab.winfo_children()[0] assert len(model_table.tree.get_children()) == 11 - assert model_table.tree.item(row1)['values'][2] == 'air' - assert model_table.tree.item(row2)['values'][3] == 'Soft Rubber-Gray-surface' - assert model_table.tree.item(row3)['values'][4] == 'True' - assert model_table.tree.item(row3)['values'][5] == 'Model' + assert model_table.tree.item(row1)["values"][2] == "air" + assert model_table.tree.item(row2)["values"][3] == "Soft Rubber-Gray-surface" + assert model_table.tree.item(row3)["values"][4] == "True" + assert model_table.tree.item(row3)["values"][5] == "Model" + -def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loader, - patched_import_data_to_project, patched_object_id): +def test_icepak_model_reviewer_table_modification( + mock_icepak_app, patched_loader, patched_import_data_to_project, patched_object_id +): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - boundary_table.tree.set(row1, column='Value 1', value='2W') - boundary_table.tree.set(row1, column='Selected Objects', value = 'CPU,KB') - boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') - boundary_table.tree.set(row3, column='Value 1', value='1.5W') + boundary_table.tree.set(row1, column="Value 1", value="2W") + boundary_table.tree.set(row1, column="Selected Objects", value="CPU,KB") + boundary_table.tree.set(row2, column="Value 1", value="2w_per_m3") + boundary_table.tree.set(row3, column="Value 1", value="1.5W") extension.update_button.invoke() - assert extension.combined_data['boundaries']['CPU']['Total Power'] == '2W' - assert extension.combined_data['boundaries']['CPU']['Objects'] == [422,150] - assert extension.combined_data['boundaries']['Memory']['Power Density'] == '2w_per_m3' - assert extension.combined_data['boundaries']['Source1']['Total Power'] == '1.5W' + assert extension.combined_data["boundaries"]["CPU"]["Total Power"] == "2W" + assert extension.combined_data["boundaries"]["CPU"]["Objects"] == [422, 150] + assert extension.combined_data["boundaries"]["Memory"]["Power Density"] == "2w_per_m3" + assert extension.combined_data["boundaries"]["Source1"]["Total Power"] == "1.5W" material_table = extension.root.materials_tab.winfo_children()[0] row1 = material_table.tree.get_children()[0] row2 = material_table.tree.get_children()[1] row3 = material_table.tree.get_children()[2] - material_table.tree.set(row1, column='Thermal Conductivity', value='150') - material_table.tree.set(row2, column='Mass Density', value='1.2') - material_table.tree.set(row3, column='Specific Heat', value='4') + material_table.tree.set(row1, column="Thermal Conductivity", value="150") + material_table.tree.set(row2, column="Mass Density", value="1.2") + material_table.tree.set(row3, column="Specific Heat", value="4") extension.update_button.invoke() - assert extension.combined_data['materials']['Al-Extruded']['thermal_conductivity'] == '150' - assert extension.combined_data['materials']['air']['mass_density'] == '1.2' - assert extension.combined_data['materials']['PCB_Material']['specific_heat'] == '4' + assert extension.combined_data["materials"]["Al-Extruded"]["thermal_conductivity"] == "150" + assert extension.combined_data["materials"]["air"]["mass_density"] == "1.2" + assert extension.combined_data["materials"]["PCB_Material"]["specific_heat"] == "4" model_table = extension.root.models_tab.winfo_children()[0] row1 = model_table.tree.get_children()[1] row2 = model_table.tree.get_children()[2] - model_table.tree.set(row1, column='Modeling', value='Non-Model') - model_table.tree.set(row2, column='Bulk Material', value = 'Al-Extruded') + model_table.tree.set(row1, column="Modeling", value="Non-Model") + model_table.tree.set(row2, column="Bulk Material", value="Al-Extruded") extension.update_button.invoke() - assert extension.combined_data['objects']['MEMORY1']['Material'] == 'Al-Extruded' - assert extension.combined_data['objects']['SERIAL_PORT']['Model'] == 'False' - - + assert extension.combined_data["objects"]["MEMORY1"]["Material"] == "Al-Extruded" + assert extension.combined_data["objects"]["SERIAL_PORT"]["Model"] == "False" From 48ba799fa38e4999d74401e4eef98ac7a2dfadb1 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:28:00 +0000 Subject: [PATCH 16/50] chore: adding changelog file 6495.added.md [dependabot-skip] --- doc/changelog.d/6495.added.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.d/6495.added.md b/doc/changelog.d/6495.added.md index ad021c6047ec..c59ed7ef1745 100644 --- a/doc/changelog.d/6495.added.md +++ b/doc/changelog.d/6495.added.md @@ -1 +1 @@ -Icepak model reviewer extension \ No newline at end of file +Icepak model reviewer extension From 2176963cde1c0566a132ffebc8eb8524591a6383 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:41:32 +0100 Subject: [PATCH 17/50] fixed documentation error --- .../icepak/icepak_model_reviewer.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst index 5b6e192ccda7..9bbf18e363c2 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst @@ -28,11 +28,11 @@ Features - Model details - Update project parameters. -Using the Extension +Using extension ------------------- 1. Open the **Automation** tab in the Icepak interface. -2. Click on the **Icepak Model Reviewer** icon under the Extension Manager. +2. Click on the **Icepak model reviewer** icon under the Extension Manager. 3. In the GUI, interact with the following elements: - **Load Project**: Load the Icepak project into the GUI. - **Update Project**: Push any modifications made in the tables back to the project. @@ -42,9 +42,10 @@ Using the Extension - **Materials**: Shows the materials used and their key properties. - **Models**: Displays model-specific data and configurations. -Each table allows inline editing of values. To commit changes, click the **Update Project** button. This will apply all modifications to the currently loaded project. +Each table allows inline editing of values. To commit changes, click the **Update Project** button. +Commit changes apply all modifications to the currently loaded project. -Tables Overview +Tables overview --------------- **Boundary Conditions Table** From f25fe0cb439a1feee08e35a27cc005c9d91e651e Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 13:46:05 +0100 Subject: [PATCH 18/50] changes to fix test --- src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py | 2 +- tests/unit/extensions/test_icepak_model_reviewer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 5d7ed1b06c38..dbbda67bd634 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -253,7 +253,7 @@ def __init__(self, withdraw: bool = False): # Initialize the common extension class with the title and theme color super().__init__( EXTENSION_TITLE, - theme_color="dark", + theme_color="light", withdraw=withdraw, add_custom_content=False, ) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 1c5aa2f4005d..5876492dd446 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -68,7 +68,7 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): assert boundary_table.tree.item(row1)['values'][5] == '4W' assert boundary_table.tree.item(row1)['values'][3] == 'CPU,KB,HEAT_SINK' assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' - assert boundary_table.tree.item(row2)['values'][3] == 'MEMORY1, MEMORY1_1' + assert boundary_table.tree.item(row2)['values'][3] == 'MEMORY1,MEMORY1_1' assert boundary_table.tree.item(row3)['values'][5] == '1W' materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 From 893daaf099c2e3434c1b538b1be97a2279129525 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 12:49:37 +0000 Subject: [PATCH 19/50] CHORE: Auto fixes from pre-commit hooks --- .../extensions/test_icepak_model_reviewer.py | 124 +++++++++++------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 5876492dd446..617fdd3d2268 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -1,46 +1,70 @@ -from textwrap import dedent -from tkinter import TclError +# -*- coding: utf-8 -*- +# +# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import json +import os from unittest.mock import patch import pytest from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer - - -import pytest -from unittest.mock import patch -import json from tests import TESTS_UNIT_PATH -import os + def config_file_load(): - config_file = os.path.join(TESTS_UNIT_PATH, 'extensions','graphics_card.json') - with open(config_file, 'r') as file: + config_file = os.path.join(TESTS_UNIT_PATH, "extensions", "graphics_card.json") + with open(config_file, "r") as file: data = json.load(file) return data + def mapping_load(): - mapping_file = os.path.join(TESTS_UNIT_PATH, 'extensions','mapping.json') - with open(mapping_file, 'r') as file: + mapping_file = os.path.join(TESTS_UNIT_PATH, "extensions", "mapping.json") + with open(mapping_file, "r") as file: data = json.load(file) return data + @pytest.fixture def patched_loader(): with patch.object(IcepakModelReviewer, "get_project_data", side_effect=config_file_load) as mock_loader: yield mock_loader + @pytest.fixture def patched_object_id(): with patch.object(IcepakModelReviewer, "object_id_mapping", side_effect=mapping_load) as mock_loader: yield mock_loader + @pytest.fixture def patched_import_data_to_project(): - with patch.object(IcepakModelReviewer, "import_data_to_project", return_value = None) as mock_loader: + with patch.object(IcepakModelReviewer, "import_data_to_project", return_value=None) as mock_loader: yield mock_loader + def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" extension = IcepakModelReviewer(withdraw=True) @@ -50,6 +74,7 @@ def test_icepak_model_reviewer(mock_icepak_app): extension.root.destroy() + def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() @@ -57,6 +82,7 @@ def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): assert boundary_table.tree is not None assert len(boundary_table.tree.get_children()) == 3 + def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() @@ -64,64 +90,64 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - assert boundary_table.tree.column(5)['id'] == 'Value 1' - assert boundary_table.tree.item(row1)['values'][5] == '4W' - assert boundary_table.tree.item(row1)['values'][3] == 'CPU,KB,HEAT_SINK' - assert boundary_table.tree.item(row2)['values'][5] == '5w_per_m3' - assert boundary_table.tree.item(row2)['values'][3] == 'MEMORY1,MEMORY1_1' - assert boundary_table.tree.item(row3)['values'][5] == '1W' + assert boundary_table.tree.column(5)["id"] == "Value 1" + assert boundary_table.tree.item(row1)["values"][5] == "4W" + assert boundary_table.tree.item(row1)["values"][3] == "CPU,KB,HEAT_SINK" + assert boundary_table.tree.item(row2)["values"][5] == "5w_per_m3" + assert boundary_table.tree.item(row2)["values"][3] == "MEMORY1,MEMORY1_1" + assert boundary_table.tree.item(row3)["values"][5] == "1W" materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 row1 = materials_table.tree.get_children()[0] row2 = materials_table.tree.get_children()[1] row3 = materials_table.tree.get_children()[2] row4 = materials_table.tree.get_children()[3] - assert materials_table.tree.item(row1)['values'][3] == 152 - assert materials_table.tree.item(row2)['values'][4] == '1.1614' - assert materials_table.tree.item(row3)['values'][5] == 2 - assert materials_table.tree.item(row4)['values'][6] == 0 + assert materials_table.tree.item(row1)["values"][3] == 152 + assert materials_table.tree.item(row2)["values"][4] == "1.1614" + assert materials_table.tree.item(row3)["values"][5] == 2 + assert materials_table.tree.item(row4)["values"][6] == 0 model_table = extension.root.models_tab.winfo_children()[0] assert len(model_table.tree.get_children()) == 11 - assert model_table.tree.item(row1)['values'][2] == 'air' - assert model_table.tree.item(row2)['values'][3] == 'Soft Rubber-Gray-surface' - assert model_table.tree.item(row3)['values'][4] == 'True' - assert model_table.tree.item(row3)['values'][5] == 'Model' + assert model_table.tree.item(row1)["values"][2] == "air" + assert model_table.tree.item(row2)["values"][3] == "Soft Rubber-Gray-surface" + assert model_table.tree.item(row3)["values"][4] == "True" + assert model_table.tree.item(row3)["values"][5] == "Model" + -def test_icepak_model_reviewer_table_modification(mock_icepak_app, patched_loader, - patched_import_data_to_project, patched_object_id): +def test_icepak_model_reviewer_table_modification( + mock_icepak_app, patched_loader, patched_import_data_to_project, patched_object_id +): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] row1 = boundary_table.tree.get_children()[0] row2 = boundary_table.tree.get_children()[1] row3 = boundary_table.tree.get_children()[2] - boundary_table.tree.set(row1, column='Value 1', value='2W') - boundary_table.tree.set(row1, column='Selected Objects', value = 'CPU,KB') - boundary_table.tree.set(row2, column='Value 1', value='2w_per_m3') - boundary_table.tree.set(row3, column='Value 1', value='1.5W') + boundary_table.tree.set(row1, column="Value 1", value="2W") + boundary_table.tree.set(row1, column="Selected Objects", value="CPU,KB") + boundary_table.tree.set(row2, column="Value 1", value="2w_per_m3") + boundary_table.tree.set(row3, column="Value 1", value="1.5W") extension.update_button.invoke() - assert extension.combined_data['boundaries']['CPU']['Total Power'] == '2W' - assert extension.combined_data['boundaries']['CPU']['Objects'] == [422,150] - assert extension.combined_data['boundaries']['Memory']['Power Density'] == '2w_per_m3' - assert extension.combined_data['boundaries']['Source1']['Total Power'] == '1.5W' + assert extension.combined_data["boundaries"]["CPU"]["Total Power"] == "2W" + assert extension.combined_data["boundaries"]["CPU"]["Objects"] == [422, 150] + assert extension.combined_data["boundaries"]["Memory"]["Power Density"] == "2w_per_m3" + assert extension.combined_data["boundaries"]["Source1"]["Total Power"] == "1.5W" material_table = extension.root.materials_tab.winfo_children()[0] row1 = material_table.tree.get_children()[0] row2 = material_table.tree.get_children()[1] row3 = material_table.tree.get_children()[2] - material_table.tree.set(row1, column='Thermal Conductivity', value='150') - material_table.tree.set(row2, column='Mass Density', value='1.2') - material_table.tree.set(row3, column='Specific Heat', value='4') + material_table.tree.set(row1, column="Thermal Conductivity", value="150") + material_table.tree.set(row2, column="Mass Density", value="1.2") + material_table.tree.set(row3, column="Specific Heat", value="4") extension.update_button.invoke() - assert extension.combined_data['materials']['Al-Extruded']['thermal_conductivity'] == '150' - assert extension.combined_data['materials']['air']['mass_density'] == '1.2' - assert extension.combined_data['materials']['PCB_Material']['specific_heat'] == '4' + assert extension.combined_data["materials"]["Al-Extruded"]["thermal_conductivity"] == "150" + assert extension.combined_data["materials"]["air"]["mass_density"] == "1.2" + assert extension.combined_data["materials"]["PCB_Material"]["specific_heat"] == "4" model_table = extension.root.models_tab.winfo_children()[0] row1 = model_table.tree.get_children()[1] row2 = model_table.tree.get_children()[2] - model_table.tree.set(row1, column='Modeling', value='Non-Model') - model_table.tree.set(row2, column='Bulk Material', value = 'Al-Extruded') + model_table.tree.set(row1, column="Modeling", value="Non-Model") + model_table.tree.set(row2, column="Bulk Material", value="Al-Extruded") extension.update_button.invoke() - assert extension.combined_data['objects']['MEMORY1']['Material'] == 'Al-Extruded' - assert extension.combined_data['objects']['SERIAL_PORT']['Model'] == 'False' - - + assert extension.combined_data["objects"]["MEMORY1"]["Material"] == "Al-Extruded" + assert extension.combined_data["objects"]["SERIAL_PORT"]["Model"] == "False" From 346fb423a924ca57cb14e25e9f3d984b00bcfe88 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 14:13:31 +0100 Subject: [PATCH 20/50] code improvement for icepak_model_reviewer.py --- .../aedt/core/extensions/icepak/icepak_model_reviewer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 57b0526aa76a..a99230ff48d1 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -26,7 +26,7 @@ import tkinter as tk from tkinter import ttk -from ansys.aedt.core import * +from ansys.aedt.core import Desktop, Icepak from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file from ansys.aedt.core.extensions.icepak.model_reviewer.backend import get_object_id_mapping from ansys.aedt.core.extensions.icepak.model_reviewer.backend import import_config_file @@ -182,7 +182,7 @@ def add_row(self, row_data): full_data = ["⬜"] + row_data self.rows_data.append(full_data) - row_id = self.tree.insert("", "end", values=full_data) + def toggle_row(self, row_id, item_index): if row_id in self.selected_rows: From 5ee99f642b4aeeb60338fe899b3bc66d9dd609e5 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 15:02:28 +0100 Subject: [PATCH 21/50] code improvement for configuration .py --- .../icepak/model_reviewer/configuration_data_processing.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 45b91d261ef6..842c77359a65 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -107,7 +107,6 @@ def extract_boundary_data(data): value1 = boundary_details.get("Total Power", "0W") value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing - # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] selected_objects = [str(ids) for ids in object_ids] boundary_data.append( [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] @@ -121,7 +120,6 @@ def extract_boundary_data(data): value1 = boundary_details.get("Temperature", "0cel") value2 = "0.0" object_ids = boundary_details.get("Faces", []) # Default to empty list if missing - # selected_objects = [id_to_name[str(obj_id)] for obj_id in object_ids] selected_objects = [str(ids) for ids in object_ids] boundary_data.append( [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] From 50e744f9c9cd75e692cc600594368f7022084e5f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 14:04:14 +0000 Subject: [PATCH 22/50] CHORE: Auto fixes from pre-commit hooks --- .../aedt/core/extensions/icepak/icepak_model_reviewer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index a99230ff48d1..db941d7a696c 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -26,7 +26,8 @@ import tkinter as tk from tkinter import ttk -from ansys.aedt.core import Desktop, Icepak +from ansys.aedt.core import Desktop +from ansys.aedt.core import Icepak from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file from ansys.aedt.core.extensions.icepak.model_reviewer.backend import get_object_id_mapping from ansys.aedt.core.extensions.icepak.model_reviewer.backend import import_config_file @@ -183,7 +184,6 @@ def add_row(self, row_data): full_data = ["⬜"] + row_data self.rows_data.append(full_data) - def toggle_row(self, row_id, item_index): if row_id in self.selected_rows: self.selected_rows.remove(row_id) From bf98056dcef8cc8ab12546b6f1b18716bb9960c4 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 15:12:56 +0100 Subject: [PATCH 23/50] code improvement for configuration .py --- .../icepak/model_reviewer/configuration_data_processing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 842c77359a65..66a9731752c5 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -261,13 +261,13 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object # Check for differences and update if isinstance(selected_objects, list): selected_object_ids = [int(i) if str(i).isdigit() else object_mapping[i] for i in selected_objects] - selected_objects_list = [i for i in selected_objects] + if isinstance(selected_objects, str): selected_object_ids = [ int(i.strip()) if str(i.strip()).isdigit() else object_mapping[i.strip()] for i in selected_objects.split(",") ] - selected_objects_list = [i.strip() for i in selected_objects.split(",")] + original_obj_ids = original_obj.get("Objects", []) if original_obj_ids: From 3e377e5b0e4391442d0212b6d65a28336a9a64db Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 14:18:28 +0000 Subject: [PATCH 24/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/model_reviewer/configuration_data_processing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 66a9731752c5..5eac67769603 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -268,7 +268,6 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object for i in selected_objects.split(",") ] - original_obj_ids = original_obj.get("Objects", []) if original_obj_ids: if set(original_obj_ids) != set(selected_object_ids): From 67438a131273b7054e2fa5b47c146f4ac6a042c8 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 15:41:16 +0100 Subject: [PATCH 25/50] change to add rows --- src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index db941d7a696c..4bc1c9ca3554 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -183,6 +183,7 @@ def add_row(self, row_data): full_data = ["⬜"] + row_data self.rows_data.append(full_data) + self.tree.insert("", "end", values=full_data) def toggle_row(self, row_id, item_index): if row_id in self.selected_rows: From af744e86b86ed786596bacffa625af142e9f8c78 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 31 Oct 2025 15:42:20 +0100 Subject: [PATCH 26/50] code improvement in configuration data processing --- .../icepak/model_reviewer/configuration_data_processing.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 66a9731752c5..37405cc85865 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -432,10 +432,3 @@ def compare_and_update_material_data(original_data, modified_object_data): return differences, modified_data -if __name__ == "__main__": - import json - - sample_json = "test1.json" - with open(sample_json, "r") as file: - data = json.load(file) - extract_boundary_data(data) From d98740142a4c74b7f8a18371624962372f096fbd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 14:50:14 +0000 Subject: [PATCH 27/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/model_reviewer/configuration_data_processing.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index d49c2f67a4eb..b9dea5662b90 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -429,5 +429,3 @@ def compare_and_update_material_data(original_data, modified_object_data): for mat_name in modified_materials: modified_data["materials"][mat_name] = copy.deepcopy(updated_data["materials"][mat_name]) return differences, modified_data - - From 37dde4d629108f51909c79e710b9a4e2e72e0208 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 3 Nov 2025 09:06:06 +0100 Subject: [PATCH 28/50] missing import in configuration test --- tests/system/general/test_01_configuration_files.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index e30a1cdd8fcf..32c095ce9477 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -25,13 +25,14 @@ # standard imports import os import time - +import json import pytest from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d +from ansys.aedt.core import Icepak from tests import TESTS_GENERAL_PATH from tests.conftest import config From c32e91f3d235f19b1a081ccb7175a7cf60c22abf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 08:07:30 +0000 Subject: [PATCH 29/50] CHORE: Auto fixes from pre-commit hooks --- tests/system/general/test_01_configuration_files.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index 32c095ce9477..5a0ef57ca7f9 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -23,16 +23,17 @@ # SOFTWARE. # standard imports +import json import os import time -import json + import pytest from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout +from ansys.aedt.core import Icepak from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d -from ansys.aedt.core import Icepak from tests import TESTS_GENERAL_PATH from tests.conftest import config From 05051ff99e048edc8293dbad5b001b02e72cb081 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 3 Nov 2025 09:22:16 +0100 Subject: [PATCH 30/50] formatting correction configuration file --- .../model_reviewer/configuration_data_processing.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index b9dea5662b90..97a416af2f69 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -171,7 +171,7 @@ def extract_model_data(data): elif surface_material == "": surface_material = "Not Specified" surface_materials.add(surface_material) - elif surface_material == None: + elif surface_material is None: surface_material = "Not Specified" surface_materials.add(surface_material) else: @@ -329,14 +329,16 @@ def compare_and_update_model_data(original_data, modified_object_data): if not surface_material == "Not Specified": if original_obj.get("SurfaceMaterial", "") != surface_material: differences.append( - f"{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to '{surface_material}'" + f"""{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to + '{surface_material}'""" ) updated_data["objects"][obj_name]["SurfaceMaterial"] = surface_material modified_objects.add(obj_name) if original_obj.get("SolveInside", "") != solve_inside_bool: differences.append( - f"{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' to '{solve_inside_bool}'" + f"""{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' + to '{solve_inside_bool}'""" ) updated_data["objects"][obj_name]["SolveInside"] = str(solve_inside_bool) modified_objects.add(obj_name) @@ -384,7 +386,8 @@ def compare_and_update_material_data(original_data, modified_object_data): if not isinstance(original_obj.get("thermal_conductivity"), dict): if original_obj.get("thermal_conductivity", "") != thermal_conductivity: differences.append( - f"{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' to '{thermal_conductivity}'" + f"""{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' + to '{thermal_conductivity}'""" ) updated_data["materials"][mat_name]["thermal_conductivity"] = thermal_conductivity modified_materials.add(mat_name) From 974fc7609557262ec587e60e672835f9957f3103 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 3 Nov 2025 09:52:51 +0100 Subject: [PATCH 31/50] formatting correction and removing changes in configuration file --- .../extensions/test_icepak_model_reviewer.py | 2 +- .../general/test_01_configuration_files.py | 155 +----------------- 2 files changed, 2 insertions(+), 155 deletions(-) diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 90f98b062ed2..7f4784b7e08b 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -115,4 +115,4 @@ def test_successfull_data_modification(ipk): model_table.tree.set(row3, column="Bulk Material", value="Al-Extruded") extension.update_button.invoke() assert ipk.modeler.objects[62].material_name == "al-extruded" - assert ipk.modeler.objects[34].model == False + assert not ipk.modeler.objects[34].model diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index 32c095ce9477..4fd8a40db9ea 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -25,14 +25,13 @@ # standard imports import os import time -import json + import pytest from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d -from ansys.aedt.core import Icepak from tests import TESTS_GENERAL_PATH from tests.conftest import config @@ -77,18 +76,6 @@ def q2dtest(add_app): return app -@pytest.fixture(scope="class") -def icepak_a(add_app): - app = add_app(project_name=ipk_name + "_a", application=Icepak) - return app - - -@pytest.fixture(scope="class") -def icepak_b(add_app): - app = add_app(project_name=ipk_name + "_b", application=Icepak) - return app - - @pytest.fixture(scope="class") def hfss3dl_a(add_app): app = add_app(project_name=diff_proj_name, application=Hfss3dLayout, subfolder=test_subfolder) @@ -187,146 +174,6 @@ def test_03_q2d_export(self, q2dtest, add_app): assert q2dtest.configurations.options.import_parametrics app.close_project(save=False) - def test_04a_icepak(self, icepak_a, aedtapp, add_app): - box1 = icepak_a.modeler.create_box([0, 0, 0], [10, 10, 10]) - icepak_a.monitor.assign_point_monitor_to_vertex(box1.vertices[0].id) - box1.surface_material_name = "Shellac-Dull-surface" - region = icepak_a.modeler["Region"] - icepak_a.monitor.assign_point_monitor_in_object(box1.name) - icepak_a.monitor.assign_face_monitor(box1.faces[0].id) - icepak_a.monitor.assign_point_monitor([5, 5, 5]) - icepak_a.assign_openings(air_faces=region.bottom_face_x.id) - icepak_a.create_setup() - icepak_a.modeler.create_coordinate_system([10, 1, 10]) - icepak_a.mesh.assign_mesh_region([box1.name]) - icepak_a.mesh.global_mesh_region.MaxElementSizeX = "2mm" - icepak_a.mesh.global_mesh_region.MaxElementSizeY = "3mm" - icepak_a.mesh.global_mesh_region.MaxElementSizeZ = "4mm" - icepak_a.mesh.global_mesh_region.MaxSizeRatio = 2 - icepak_a.mesh.global_mesh_region.UserSpecifiedSettings = True - icepak_a.mesh.global_mesh_region.UniformMeshParametersType = "XYZ Max Sizes" - icepak_a.mesh.global_mesh_region.MaxLevels = 2 - icepak_a.mesh.global_mesh_region.BufferLayers = 1 - icepak_a.mesh.global_mesh_region.update() - cs = aedtapp.modeler.create_coordinate_system(name="useless") - cs.props["OriginX"] = 20 - cs.props["OriginY"] = 20 - cs.props["OriginZ"] = 20 - icepak_a.create_dataset( - "test_dataset", - [1, 2, 3, 4], - [1, 2, 3, 4], - z=None, - v=None, - is_project_dataset=False, - x_unit="cel", - y_unit="W", - v_unit="", - ) - filename = icepak_a.design_name - icepak_a.export_3d_model(filename, icepak_a.working_directory, ".x_b", [], []) - assert icepak_a.configurations.options.export_monitor - assert icepak_a.configurations.options.export_native_components - assert icepak_a.configurations.options.export_datasets - conf_file = icepak_a.configurations.export_config() - assert icepak_a.configurations.validate(conf_file) - f = icepak_a.create_fan("test_fan") - idx = 0 - icepak_a.monitor.assign_point_monitor_to_vertex( - list(icepak_a.modeler.user_defined_components[f.name].parts.values())[idx].vertices[0].id - ) - assert icepak_a.configurations.export_config() - f.delete() - file_path = os.path.join(icepak_a.working_directory, filename + ".x_b") - app = add_app(application=Icepak, project_name="new_proj_Ipk_a", just_open=True) - app.modeler.import_3d_cad(file_path) - out = app.configurations.import_config(conf_file) - assert isinstance(out, dict) - assert app.configurations.validate(out) - assert app.configurations.results.global_import_success - # backward compatibility - with open(conf_file, "r") as f: - old_dict_format = json.load(f) - old_dict_format["monitor"] = old_dict_format.pop("monitors") - old_mon_dict = {} - for mon in old_dict_format["monitor"]: - old_mon_dict[mon["Name"]] = mon - old_mon_dict[mon["Name"]].pop("Name") - old_dict_format["monitor"] = old_mon_dict - old_dataset_dict = {} - for dat in old_dict_format["datasets"]: - old_dataset_dict[dat["Name"]] = dat - old_dataset_dict[dat["Name"]].pop("Name") - old_dict_format["datasets"] = old_dataset_dict - old_conf_file = conf_file + ".old.json" - with open(old_conf_file, "w") as f: - json.dump(old_dict_format, f) - app = add_app(application=Icepak, project_name="new_proj_Ipk_a_test2", just_open=True) - app.modeler.import_3d_cad(file_path) - out = app.configurations.import_config(old_conf_file) - assert isinstance(out, dict) - assert app.configurations.results.global_import_success - app.close_project(save=False) - - @pytest.mark.skipif( - config["desktopVersion"] < "2023.1" and config["use_grpc"], - reason="Not working in 2022.2 gRPC", - ) - def test_04b_icepak(self, icepak_b, add_app): - box1 = icepak_b.modeler.create_box([0, 0, 0], [10, 10, 10]) - box1.surface_material_name = "Shellac-Dull-surface" - region = icepak_b.modeler["Region"] - icepak_b.monitor.assign_point_monitor_in_object(box1.name) - icepak_b.monitor.assign_face_monitor(box1.faces[0].id) - icepak_b.monitor.assign_point_monitor([5, 5, 5]) - icepak_b.assign_openings(air_faces=region.bottom_face_x.id) - icepak_b.create_setup() - icepak_b.modeler.create_coordinate_system([10, 1, 10]) - icepak_b.mesh.assign_mesh_region([box1.name]) - icepak_b.mesh.global_mesh_region.MaxElementSizeX = "2mm" - icepak_b.mesh.global_mesh_region.MaxElementSizeY = "3mm" - icepak_b.mesh.global_mesh_region.MaxElementSizeZ = "4mm" - icepak_b.mesh.global_mesh_region.MaxSizeRatio = 2 - icepak_b.mesh.global_mesh_region.UserSpecifiedSettings = True - icepak_b.mesh.global_mesh_region.UniformMeshParametersType = "XYZ Max Sizes" - icepak_b.mesh.global_mesh_region.MaxLevels = 2 - icepak_b.mesh.global_mesh_region.BufferLayers = 1 - icepak_b.mesh.global_mesh_region.update() - cs = icepak_b.modeler.create_coordinate_system(name="useless") - cs.props["OriginX"] = 20 - cs.props["OriginY"] = 20 - cs.props["OriginZ"] = 20 - icepak_b.create_dataset( - "test_dataset", - [1, 2, 3, 4], - [1, 2, 3, 4], - z=None, - v=None, - is_project_dataset=False, - x_unit="cel", - y_unit="W", - v_unit="", - ) - filename = icepak_b.design_name - icepak_b.export_3d_model(filename, icepak_b.working_directory, ".x_b", [], []) - fan = icepak_b.create_fan("test_fan") - icepak_b.modeler.user_defined_components[fan.name].move([1, 2, 3]) - fan2 = icepak_b.modeler.user_defined_components[fan.name].duplicate_along_line([4, 5, 6]) - icepak_b.modeler.user_defined_components[fan.name].rotate("Y") - fan3 = icepak_b.modeler.user_defined_components[fan.name].duplicate_around_axis("Z") - icepak_b.modeler.user_defined_components[fan.name].move([1, 2, 3]) - fan4 = icepak_b.modeler.user_defined_components[fan.name].duplicate_around_axis("Z") - icepak_b.modeler.user_defined_components[fan2[0]].duplicate_and_mirror([4, 5, 6], [1, 2, 3]) - conf_file = icepak_b.configurations.export_config() - assert icepak_b.configurations.validate(conf_file) - file_path = os.path.join(icepak_b.working_directory, filename + ".x_b") - app = add_app(application=Icepak, project_name="new_proj_Ipk", just_open=True) - app.modeler.import_3d_cad(file_path) - out = app.configurations.import_config(conf_file) - assert isinstance(out, dict) - assert app.configurations.validate(out) - assert app.configurations.results.global_import_success - def test_05a_hfss3dlayout_setup(self, hfss3dl_a, local_scratch): setup2 = hfss3dl_a.create_setup("My_HFSS_Setup_2") # Insert a setup. assert setup2.props["ViaNumSides"] == 6 # Check the default value. From 07903a9dc561f9bebe0617632caddc43dc9c8ac6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 08:54:12 +0000 Subject: [PATCH 32/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/model_reviewer/configuration_data_processing.py | 6 +++--- tests/system/general/test_01_configuration_files.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 97a416af2f69..89e275b1980d 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -329,7 +329,7 @@ def compare_and_update_model_data(original_data, modified_object_data): if not surface_material == "Not Specified": if original_obj.get("SurfaceMaterial", "") != surface_material: differences.append( - f"""{obj_name}: Surface Material changed from '{original_obj.get('SurfaceMaterial', '')}' to + f"""{obj_name}: Surface Material changed from '{original_obj.get("SurfaceMaterial", "")}' to '{surface_material}'""" ) updated_data["objects"][obj_name]["SurfaceMaterial"] = surface_material @@ -337,7 +337,7 @@ def compare_and_update_model_data(original_data, modified_object_data): if original_obj.get("SolveInside", "") != solve_inside_bool: differences.append( - f"""{obj_name}: Solve Inside changed from '{original_obj.get('SolveInside', '')}' + f"""{obj_name}: Solve Inside changed from '{original_obj.get("SolveInside", "")}' to '{solve_inside_bool}'""" ) updated_data["objects"][obj_name]["SolveInside"] = str(solve_inside_bool) @@ -386,7 +386,7 @@ def compare_and_update_material_data(original_data, modified_object_data): if not isinstance(original_obj.get("thermal_conductivity"), dict): if original_obj.get("thermal_conductivity", "") != thermal_conductivity: differences.append( - f"""{mat_name}: Thermal Conductivity changed from '{original_obj.get('thermal_conductivity', '')}' + f"""{mat_name}: Thermal Conductivity changed from '{original_obj.get("thermal_conductivity", "")}' to '{thermal_conductivity}'""" ) updated_data["materials"][mat_name]["thermal_conductivity"] = thermal_conductivity diff --git a/tests/system/general/test_01_configuration_files.py b/tests/system/general/test_01_configuration_files.py index e590423d73e1..4fd8a40db9ea 100644 --- a/tests/system/general/test_01_configuration_files.py +++ b/tests/system/general/test_01_configuration_files.py @@ -23,7 +23,6 @@ # SOFTWARE. # standard imports -import json import os import time @@ -31,7 +30,6 @@ from ansys.aedt.core import Circuit from ansys.aedt.core import Hfss3dLayout -from ansys.aedt.core import Icepak from ansys.aedt.core import Q2d from ansys.aedt.core import Q3d from tests import TESTS_GENERAL_PATH From 5ae15ab522d25a4fbcb2a43f307c28f50e60a4c3 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 6 Nov 2025 12:29:13 +0100 Subject: [PATCH 33/50] additional test cases for table class --- .../extensions/test_icepak_model_reviewer.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 617fdd3d2268..dcfb370c0c31 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -113,6 +113,71 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): assert model_table.tree.item(row3)["values"][4] == "True" assert model_table.tree.item(row3)["values"][5] == "Model" +def test_table_icon_handling_after_load(mock_icepak_app, patched_loader): + """Verify that all read-only cells in the table have the 🔒 icon appended.""" + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + + for tab_name in ["boundary_tab", "materials_tab", "models_tab"]: + table = getattr(extension.root, tab_name).winfo_children()[0] + tree = table.tree + rows = tree.get_children() + # For every row, check each read-only column + for row_index, row_id in enumerate(rows): + values = tree.item(row_id)["values"] + readonly_cols = table.read_only_data[row_index] + + for col_index, value in enumerate(values): # 1-based index for consistency + val_str = str(value) + if col_index in readonly_cols: + assert val_str.endswith("🔒") + else: + assert not val_str.endswith("🔒") + +def test_table_headers_and_types_consistency(mock_icepak_app, patched_loader): + """ + Verify: + - each table has consistent header/type pairing + - 'multiple_text' columns contain comma-separated values + """ + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + + for tab_name in ["boundary_tab", "materials_tab", "models_tab"]: + table = getattr(extension.root, tab_name).winfo_children()[0] + headers = table.headers + types = table.types + tree = table.tree + + # --- 1Check header/type consistency --- + assert len(headers) == len(types), f"{tab_name} headers/types mismatch" + + # --- multiple_text columns should have comma-separated values --- + multi_text_indices = [i for i, t in enumerate(types) if t == "multiple_text"] + if multi_text_indices: + found_multi = False + for row_id in tree.get_children(): + values = tree.item(row_id)["values"] + for idx in multi_text_indices: + if idx < len(values) and "," in str(values[idx]): + found_multi = True + break + if found_multi: + break + assert found_multi + +def test_table_reload_does_not_duplicate(mock_icepak_app, patched_loader): + """Ensure multiple loads don't duplicate table entries.""" + extension = IcepakModelReviewer(withdraw=True) + + extension.load_button.invoke() + first_load_rows = len(extension.root.boundary_tab.winfo_children()[0].tree.get_children()) + + # Invoke load again + extension.load_button.invoke() + second_load_rows = len(extension.root.boundary_tab.winfo_children()[0].tree.get_children()) + + assert first_load_rows == second_load_rows def test_icepak_model_reviewer_table_modification( mock_icepak_app, patched_loader, patched_import_data_to_project, patched_object_id @@ -151,3 +216,6 @@ def test_icepak_model_reviewer_table_modification( extension.update_button.invoke() assert extension.combined_data["objects"]["MEMORY1"]["Material"] == "Al-Extruded" assert extension.combined_data["objects"]["SERIAL_PORT"]["Model"] == "False" + + + From f383d0e875f7bfd7f9a30eda56c65510d01faaf0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 11:32:41 +0000 Subject: [PATCH 34/50] CHORE: Auto fixes from pre-commit hooks --- tests/unit/extensions/test_icepak_model_reviewer.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index dcfb370c0c31..f69b53b92682 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -113,6 +113,7 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): assert model_table.tree.item(row3)["values"][4] == "True" assert model_table.tree.item(row3)["values"][5] == "Model" + def test_table_icon_handling_after_load(mock_icepak_app, patched_loader): """Verify that all read-only cells in the table have the 🔒 icon appended.""" extension = IcepakModelReviewer(withdraw=True) @@ -134,6 +135,7 @@ def test_table_icon_handling_after_load(mock_icepak_app, patched_loader): else: assert not val_str.endswith("🔒") + def test_table_headers_and_types_consistency(mock_icepak_app, patched_loader): """ Verify: @@ -166,6 +168,7 @@ def test_table_headers_and_types_consistency(mock_icepak_app, patched_loader): break assert found_multi + def test_table_reload_does_not_duplicate(mock_icepak_app, patched_loader): """Ensure multiple loads don't duplicate table entries.""" extension = IcepakModelReviewer(withdraw=True) @@ -179,6 +182,7 @@ def test_table_reload_does_not_duplicate(mock_icepak_app, patched_loader): assert first_load_rows == second_load_rows + def test_icepak_model_reviewer_table_modification( mock_icepak_app, patched_loader, patched_import_data_to_project, patched_object_id ): @@ -216,6 +220,3 @@ def test_icepak_model_reviewer_table_modification( extension.update_button.invoke() assert extension.combined_data["objects"]["MEMORY1"]["Material"] == "Al-Extruded" assert extension.combined_data["objects"]["SERIAL_PORT"]["Model"] == "False" - - - From d4335fbbe1487100d647848d8ace8a8f4829eee8 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 10 Nov 2025 16:07:04 +0100 Subject: [PATCH 35/50] additional test cases for table class --- .../unit/extensions/test_icepak_model_reviewer.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index dcfb370c0c31..57e5569fbc44 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -82,14 +82,11 @@ def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): assert boundary_table.tree is not None assert len(boundary_table.tree.get_children()) == 3 - def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] - row1 = boundary_table.tree.get_children()[0] - row2 = boundary_table.tree.get_children()[1] - row3 = boundary_table.tree.get_children()[2] + row1, row2, row3 = boundary_table.tree.get_children()[:3] assert boundary_table.tree.column(5)["id"] == "Value 1" assert boundary_table.tree.item(row1)["values"][5] == "4W" assert boundary_table.tree.item(row1)["values"][3] == "CPU,KB,HEAT_SINK" @@ -98,16 +95,17 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): assert boundary_table.tree.item(row3)["values"][5] == "1W" materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 - row1 = materials_table.tree.get_children()[0] - row2 = materials_table.tree.get_children()[1] - row3 = materials_table.tree.get_children()[2] - row4 = materials_table.tree.get_children()[3] + row1, row2, row3, row4 = materials_table.tree.get_children()[:4] + assert materials_table.tree.item(row1)["values"][1] == 'Al-Extruded🔒' + assert materials_table.tree.item(row1)["values"][2] == 'Solid🔒' assert materials_table.tree.item(row1)["values"][3] == 152 + assert materials_table.tree.item(row1)["values"][4] == 2000 assert materials_table.tree.item(row2)["values"][4] == "1.1614" assert materials_table.tree.item(row3)["values"][5] == 2 assert materials_table.tree.item(row4)["values"][6] == 0 model_table = extension.root.models_tab.winfo_children()[0] assert len(model_table.tree.get_children()) == 11 + row1, row2, row3 = model_table.tree.get_children()[:3] assert model_table.tree.item(row1)["values"][2] == "air" assert model_table.tree.item(row2)["values"][3] == "Soft Rubber-Gray-surface" assert model_table.tree.item(row3)["values"][4] == "True" From ca72929b8dbda5d1d6c5458d53d01d4498b15fef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:19:49 +0000 Subject: [PATCH 36/50] CHORE: Auto fixes from pre-commit hooks --- tests/unit/extensions/test_icepak_model_reviewer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index ac3b94bede1e..49b3177eafef 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -82,6 +82,7 @@ def test_icepak_model_reviewer_load_project(mock_icepak_app, patched_loader): assert boundary_table.tree is not None assert len(boundary_table.tree.get_children()) == 3 + def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() @@ -96,8 +97,8 @@ def test_icepak_model_reviewer_table_values(mock_icepak_app, patched_loader): materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 row1, row2, row3, row4 = materials_table.tree.get_children()[:4] - assert materials_table.tree.item(row1)["values"][1] == 'Al-Extruded🔒' - assert materials_table.tree.item(row1)["values"][2] == 'Solid🔒' + assert materials_table.tree.item(row1)["values"][1] == "Al-Extruded🔒" + assert materials_table.tree.item(row1)["values"][2] == "Solid🔒" assert materials_table.tree.item(row1)["values"][3] == 152 assert materials_table.tree.item(row1)["values"][4] == 2000 assert materials_table.tree.item(row2)["values"][4] == "1.1614" From 13699e589ab57e08bbac7c785acb34f755933926 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Wed, 17 Dec 2025 11:55:21 +0100 Subject: [PATCH 37/50] changes in json for test case --- src/ansys/aedt/core/extensions/icepak/load.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/ansys/aedt/core/extensions/icepak/load.json diff --git a/src/ansys/aedt/core/extensions/icepak/load.json b/src/ansys/aedt/core/extensions/icepak/load.json new file mode 100644 index 000000000000..f3f73c4468bc --- /dev/null +++ b/src/ansys/aedt/core/extensions/icepak/load.json @@ -0,0 +1 @@ +{"objects": {}, "materials": {}, "boundaries": {"CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [150, 422], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "4W"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "134": "CAPACITOR_1", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file From ef9a5548233db2281df62bd28c2653f0d0d3af42 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 29 Dec 2025 13:24:09 +0100 Subject: [PATCH 38/50] additional test cases for table class cell update --- .../icepak/icepak_model_reviewer.py | 30 ++++++++------ .../extensions/test_icepak_model_reviewer.py | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 4bc1c9ca3554..a63b8566f91e 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -185,7 +185,7 @@ def add_row(self, row_data): self.rows_data.append(full_data) self.tree.insert("", "end", values=full_data) - def toggle_row(self, row_id, item_index): + def toggle_row(self, row_id): if row_id in self.selected_rows: self.selected_rows.remove(row_id) self.tree.set(row_id, 0, "⬜") @@ -196,6 +196,21 @@ def toggle_row(self, row_id, item_index): def get_modified_data(self): return [self.tree.item(row)["values"][1:] for row in self.tree.get_children()] + def update_cell_value(self, row_id, col, new_value): + """Modified data update logic decoupled from UI events.""" + # Determine which rows to update (bulk edit if selected) + if row_id in self.selected_rows: + targets = self.selected_rows + else: + targets = {row_id} + for rid in targets: + idx = self.tree.index(rid) + # Check read-only constraint + if col not in self.read_only_data[idx]: + self.tree.set(rid, col, new_value) + # Update the underlying data list + self.rows_data[idx][col] = new_value + def edit_cell(self, event): region = self.tree.identify("region", event.x, event.y) if region != "cell": @@ -206,7 +221,7 @@ def edit_cell(self, event): item_index = self.tree.index(row_id) if col == 0: - self.toggle_row(row_id, item_index) + self.toggle_row(row_id) return if col in self.read_only_data[item_index]: @@ -225,16 +240,7 @@ def edit_cell(self, event): type_ = self.types[col] def apply_to_selected(new_value): - for rid in self.tree.get_children(): - if row_id in self.selected_rows: - targets = self.selected_rows - else: - targets = {row_id} - if rid in targets: - idx = self.tree.index(rid) - if col not in self.read_only_data[idx]: - self.tree.set(rid, col, new_value) - self.rows_data[idx][col] = new_value + self.update_cell_value(row_id, col, new_value) if type_ == "text": entry = tk.Entry(self.tree) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 49b3177eafef..de3b6a3213d4 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -27,9 +27,12 @@ from unittest.mock import patch import pytest +import tkinter as tk +from tkinter import ttk from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import Table from tests import TESTS_UNIT_PATH @@ -65,6 +68,22 @@ def patched_import_data_to_project(): yield mock_loader +@pytest.fixture +def table_instance(): + + """Setup a table instance for testing.""" + root = tk.Tk() + headers = ["Name", "Status"] + types = ["text", "combo"] + # Row 0: Column 1 (Name) is read-only + # Row 1: No read-only columns + read_only_data = [{1}, set()] + + table = Table(root, headers, types, read_only_data) + table.add_row(["Alice", "Active"]) + table.add_row(["Bob", "Inactive"]) + return table + def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" extension = IcepakModelReviewer(withdraw=True) @@ -219,3 +238,25 @@ def test_icepak_model_reviewer_table_modification( extension.update_button.invoke() assert extension.combined_data["objects"]["MEMORY1"]["Material"] == "Al-Extruded" assert extension.combined_data["objects"]["SERIAL_PORT"]["Model"] == "False" + + +def test_icepak_table_modification(mock_icepak_app, patched_loader): + extension = IcepakModelReviewer(withdraw=True) + extension.load_button.invoke() + + boundary_table = extension.root.boundary_tab.winfo_children()[0] + row1 = boundary_table.tree.get_children()[0] + + # 1. TEST PROGRAMMATIC MODIFICATION + # Simulates changing 'Value 1' (Col 5) to '10W' + boundary_table.update_cell_value(row1, 5, "10W") + assert boundary_table.tree.item(row1)["values"][5] == "10W" + + # 2. TEST BULK EDITING (UI Logic Coverage) + row3 = boundary_table.tree.get_children()[2] + boundary_table.toggle_row(row1) # Select row 1 + boundary_table.toggle_row(row3) # Select row 2 + + # Modifying row1 should now also modify row2 + boundary_table.update_cell_value(row1, 5, "99W") + assert boundary_table.tree.item(row3)["values"][5] == "99W" \ No newline at end of file From c3c0da336a31e44148681e4a6033cf85de37c83c Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 8 Jan 2026 12:37:02 +0100 Subject: [PATCH 39/50] additional test cases for UI operations text editing and combo selection --- .../extensions/test_icepak_model_reviewer.py | 113 +++++++++++++++--- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index de3b6a3213d4..a45f82d6084e 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -30,10 +30,19 @@ import tkinter as tk from tkinter import ttk -from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE, add_table_to_tab from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer +from ansys.aedt.core.extensions.misc import ExtensionTheme from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import Table from tests import TESTS_UNIT_PATH +from ansys.aedt.core.icepak import Icepak +from pathlib import Path + +AEDT_FILENAME = "Graphics_Card" +CONFIG_FILE = "Modified_Data.json" +TEST_SUBFOLDER = "T45" +AEDT_FILE_PATH = Path(__file__).parent / "example_models" / TEST_SUBFOLDER / (AEDT_FILENAME + ".aedt") + def config_file_load(): @@ -50,6 +59,7 @@ def mapping_load(): return data + @pytest.fixture def patched_loader(): with patch.object(IcepakModelReviewer, "get_project_data", side_effect=config_file_load) as mock_loader: @@ -68,21 +78,90 @@ def patched_import_data_to_project(): yield mock_loader -@pytest.fixture -def table_instance(): +theme = ExtensionTheme() + + +def add_icon_to_cells(data, read_only): return data - """Setup a table instance for testing.""" + +def flatten_list(data): return data + + +# --- Pytest Fixture --- +@pytest.fixture +def table_app(): root = tk.Tk() - headers = ["Name", "Status"] - types = ["text", "combo"] - # Row 0: Column 1 (Name) is read-only - # Row 1: No read-only columns - read_only_data = [{1}, set()] + root.geometry("800x500") # Set a size so it's visible + #root.withdraw() + # --- 1. MOCK DATA --- + headings = ["Name", "Type", "Objects"] + type_list = ["text", "combo", "multiple_text"] + selection_dict = { + "Category": ["Solid", "Fluid"], + "Tags": ["CPU", "DDR", "RAM"] + } + row_data = [["BC1", "Solid", "CPU"]] + read_only_cols = [[]] + + # --- 2. CORRECT LAYOUT --- + notebook = ttk.Notebook(root) + notebook.pack(fill="both", expand=True) # Must pack the notebook! + + tab = ttk.Frame(notebook) + notebook.add(tab, text="Mock Tab") # Must add the frame to the notebook! + + table_data = (headings, type_list, selection_dict, row_data, read_only_cols) + table = add_table_to_tab(tab, table_data) + + # --- 3. PROCESS EVENTS WITHOUT BLOCKING --- + root.update_idletasks() + root.update() + #root.mainloop() + # We do NOT use root.mainloop() here because it blocks pytest. + # root.update() is enough to render the window for the test. + + yield root, table + + root.destroy() +# --- Main Test Case --- +def test_ui_edit_workflow(table_app): + root, table = table_app + tree = table.tree + row_id = tree.get_children()[0] + tree.see(row_id) + # ========================================================== + # 1. TESTING THE 'TEXT' COLUMN (#2) + # ========================================================== + # Locate cell, simulate click, and type text + x, y, w, h = tree.bbox(row_id, "#2") + event = tk.Event() + event.x, event.y = x + 200, y + 20 + table.edit_cell(event) + + # Find the Entry widget that was dynamically created + entry = next(c for c in tree.winfo_children() if isinstance(c, tk.Entry)) + entry.delete(0, tk.END) + entry.insert(0, "BC2") + tree.update() + entry.event_generate("") # Simulate pressing Enter to save + assert tree.set(row_id, "#2") == "BC2" + + # ========================================================== + # 2. TESTING THE 'COMBO' COLUMN (#3) + # ========================================================== + # Locate cell, simulate click, and select from dropdown + x, y, w, h = tree.bbox(row_id, "#3") + event.x, event.y = x + 200, y + 20 + table.edit_cell(event) + + # Find the Combobox widget that was dynamically created + combo = next(c for c in tree.winfo_children() if isinstance(c, ttk.Combobox)) + combo.set("Fluid") + combo.event_generate("<>") # Trigger selection event + tree.update() + assert tree.set(row_id, "#3") == "Fluid" + - table = Table(root, headers, types, read_only_data) - table.add_row(["Alice", "Active"]) - table.add_row(["Bob", "Inactive"]) - return table def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" @@ -253,10 +332,14 @@ def test_icepak_table_modification(mock_icepak_app, patched_loader): assert boundary_table.tree.item(row1)["values"][5] == "10W" # 2. TEST BULK EDITING (UI Logic Coverage) + row2 = boundary_table.tree.get_children()[2] row3 = boundary_table.tree.get_children()[2] boundary_table.toggle_row(row1) # Select row 1 - boundary_table.toggle_row(row3) # Select row 2 + boundary_table.toggle_row(row2) # Select row 2 + boundary_table.toggle_row(row2) # Unselect row 2 + boundary_table.toggle_row(row3) # Select row 3 # Modifying row1 should now also modify row2 boundary_table.update_cell_value(row1, 5, "99W") - assert boundary_table.tree.item(row3)["values"][5] == "99W" \ No newline at end of file + assert boundary_table.tree.item(row3)["values"][5] == "99W" + From 92d9318d9f41fdf448f12784f72ad3e6a9648beb Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 8 Jan 2026 15:12:21 +0100 Subject: [PATCH 40/50] additional test cases for UI operations Multiple text editing and selection --- .../extensions/test_icepak_model_reviewer.py | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index a45f82d6084e..713ec0390ad8 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -97,10 +97,10 @@ def table_app(): headings = ["Name", "Type", "Objects"] type_list = ["text", "combo", "multiple_text"] selection_dict = { - "Category": ["Solid", "Fluid"], - "Tags": ["CPU", "DDR", "RAM"] + "Type": ["Solid", "Fluid"], + "Objects": ["CPU", "DDR", "RAM"] } - row_data = [["BC1", "Solid", "CPU"]] + row_data = [["BC1", "Solid", ["CPU"]]] read_only_cols = [[]] # --- 2. CORRECT LAYOUT --- @@ -161,6 +161,41 @@ def test_ui_edit_workflow(table_app): tree.update() assert tree.set(row_id, "#3") == "Fluid" + # ========================================================== + # 3. TESTING THE 'MULTIPLE_TEXT' COLUMN (#4) + # ========================================================== + x, y, w, h = tree.bbox(row_id, "#4") + event.x, event.y = x + 200, y + 20 # Adjust to hit the cell + + def handle_toplevel(): + # 1. Find the Toplevel window + # We look for a Toplevel that is a child of the table + top = next(c for c in table.winfo_children() if isinstance(c, tk.Toplevel)) + + # 2. Find the Listbox inside that Toplevel + listbox = next(c for c in top.winfo_children() if isinstance(c, tk.Listbox)) + + # 3. Select specific indices (e.g., first and second items) + listbox.selection_clear(0, tk.END) + listbox.selection_set(0) + listbox.selection_set(1) + + # 4. Find and click the 'OK' button + ok_btn = next(c for c in top.winfo_children() if isinstance(c, ttk.Button)) + ok_btn.invoke() + + # Schedule the handler to run once the mainloop starts waiting for the window + table.after(100, handle_toplevel) + + # This call will block due to self.wait_window(top), + # but the after() scheduled above will execute. + table.edit_cell(event) + tree.update() + # Verify the result (comma-separated string) + # Note: Ensure these expected values match your multi_select_options + # expected_val = f"{table.multi_select_options[table.headers[3]][0]}, {table.multi_select_options[table.headers[3]][1]}" + assert tree.set(row_id, "#4") == "CPU, DDR" + def test_icepak_model_reviewer(mock_icepak_app): From cb2aad4a451c6d0e2d92b50953d4f650a599ac34 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 14:14:14 +0000 Subject: [PATCH 41/50] CHORE: Auto fixes from pre-commit hooks --- .../icepak/icepak_model_reviewer.py | 2 +- .../icepak/model_reviewer/__init__.py | 2 +- .../icepak/model_reviewer/backend.py | 2 +- .../configuration_data_processing.py | 2 +- .../extensions/test_icepak_model_reviewer.py | 2 +- .../extensions/test_icepak_model_reviewer.py | 38 +++++++++---------- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index a63b8566f91e..2d02b9c149f2 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py index b78d8fed76c9..cbf2c1ee853b 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index eab14885ea48..017c5bc08b12 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 89e275b1980d..b54250270cb4 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 7f4784b7e08b..698f6be94837 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 713ec0390ad8..bcc4d439e3c4 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates. +# Copyright (C) 2021 - 2026 ANSYS, Inc. and/or its affiliates. # SPDX-License-Identifier: MIT # # @@ -24,19 +24,18 @@ import json import os +from pathlib import Path +import tkinter as tk +from tkinter import ttk from unittest.mock import patch import pytest -import tkinter as tk -from tkinter import ttk -from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE, add_table_to_tab +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer +from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import add_table_to_tab from ansys.aedt.core.extensions.misc import ExtensionTheme -from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import Table from tests import TESTS_UNIT_PATH -from ansys.aedt.core.icepak import Icepak -from pathlib import Path AEDT_FILENAME = "Graphics_Card" CONFIG_FILE = "Modified_Data.json" @@ -44,7 +43,6 @@ AEDT_FILE_PATH = Path(__file__).parent / "example_models" / TEST_SUBFOLDER / (AEDT_FILENAME + ".aedt") - def config_file_load(): config_file = os.path.join(TESTS_UNIT_PATH, "extensions", "graphics_card.json") with open(config_file, "r") as file: @@ -59,7 +57,6 @@ def mapping_load(): return data - @pytest.fixture def patched_loader(): with patch.object(IcepakModelReviewer, "get_project_data", side_effect=config_file_load) as mock_loader: @@ -81,10 +78,12 @@ def patched_import_data_to_project(): theme = ExtensionTheme() -def add_icon_to_cells(data, read_only): return data +def add_icon_to_cells(data, read_only): + return data -def flatten_list(data): return data +def flatten_list(data): + return data # --- Pytest Fixture --- @@ -92,14 +91,11 @@ def flatten_list(data): return data def table_app(): root = tk.Tk() root.geometry("800x500") # Set a size so it's visible - #root.withdraw() + # root.withdraw() # --- 1. MOCK DATA --- headings = ["Name", "Type", "Objects"] type_list = ["text", "combo", "multiple_text"] - selection_dict = { - "Type": ["Solid", "Fluid"], - "Objects": ["CPU", "DDR", "RAM"] - } + selection_dict = {"Type": ["Solid", "Fluid"], "Objects": ["CPU", "DDR", "RAM"]} row_data = [["BC1", "Solid", ["CPU"]]] read_only_cols = [[]] @@ -116,13 +112,15 @@ def table_app(): # --- 3. PROCESS EVENTS WITHOUT BLOCKING --- root.update_idletasks() root.update() - #root.mainloop() + # root.mainloop() # We do NOT use root.mainloop() here because it blocks pytest. # root.update() is enough to render the window for the test. yield root, table root.destroy() + + # --- Main Test Case --- def test_ui_edit_workflow(table_app): root, table = table_app @@ -197,7 +195,6 @@ def handle_toplevel(): assert tree.set(row_id, "#4") == "CPU, DDR" - def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" extension = IcepakModelReviewer(withdraw=True) @@ -370,11 +367,10 @@ def test_icepak_table_modification(mock_icepak_app, patched_loader): row2 = boundary_table.tree.get_children()[2] row3 = boundary_table.tree.get_children()[2] boundary_table.toggle_row(row1) # Select row 1 - boundary_table.toggle_row(row2) # Select row 2 - boundary_table.toggle_row(row2) # Unselect row 2 + boundary_table.toggle_row(row2) # Select row 2 + boundary_table.toggle_row(row2) # Unselect row 2 boundary_table.toggle_row(row3) # Select row 3 # Modifying row1 should now also modify row2 boundary_table.update_cell_value(row1, 5, "99W") assert boundary_table.tree.item(row3)["values"][5] == "99W" - From 2708d80dbdfde407c82588b103f68fa14b1910af Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Mon, 12 Jan 2026 15:23:01 +0100 Subject: [PATCH 42/50] additional test cases for import and export of json data --- .../extensions/icepak/model_reviewer/backend.py | 2 +- .../extensions/test_icepak_model_reviewer.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index eab14885ea48..3afb098c7019 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -50,7 +50,7 @@ def import_config_file(aedtapp, json_data): aedtapp.logger.info("Sucessfully imported configuration") else: aedtapp.logger.info("Import has issues") - return None + return result def get_object_id_mapping(aedtapp): diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 7f4784b7e08b..59ca84dbb2b6 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -23,11 +23,13 @@ # SOFTWARE. from pathlib import Path - +import tempfile import pytest - +import json from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, import_config_file from ansys.aedt.core.icepak import Icepak +from tests.unit.extensions.test_mcad_assembly import local_scratch AEDT_FILENAME = "Graphics_Card" CONFIG_FILE = "Modified_Data.json" @@ -45,6 +47,14 @@ def ipk(add_app, request): yield app app.close_project(app.project_name, False) +@pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) +def test_successfull_json_export_import(ipk): + # 1. Dump data to the file + exported_data = export_config_file(ipk) + assert ipk.configurations.options.export_monitor is False + assert ipk.configurations.options.export_variables is False + result = import_config_file(ipk, exported_data) + assert result is True @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_data_loading(ipk): From cb9f2097b3c4ee0aede543dcffe6a69f76326fd3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:24:22 +0000 Subject: [PATCH 43/50] CHORE: Auto fixes from pre-commit hooks --- tests/system/extensions/test_icepak_model_reviewer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index d13ff6e64f4e..bc639e44dd20 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -23,13 +23,13 @@ # SOFTWARE. from pathlib import Path -import tempfile + import pytest -import json + from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer -from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file, import_config_file +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import export_config_file +from ansys.aedt.core.extensions.icepak.model_reviewer.backend import import_config_file from ansys.aedt.core.icepak import Icepak -from tests.unit.extensions.test_mcad_assembly import local_scratch AEDT_FILENAME = "Graphics_Card" CONFIG_FILE = "Modified_Data.json" @@ -47,6 +47,7 @@ def ipk(add_app, request): yield app app.close_project(app.project_name, False) + @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_json_export_import(ipk): # 1. Dump data to the file @@ -56,6 +57,7 @@ def test_successfull_json_export_import(ipk): result = import_config_file(ipk, exported_data) assert result is True + @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_data_loading(ipk): """Test the successful execution of the power map creation in Icepak.""" From 33f422f3249c50104b9f3e02ef5aca4f104a6fa6 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 29 Jan 2026 12:00:31 +0100 Subject: [PATCH 44/50] additional test cases to cover all boundaries and materials --- .../icepak/icepak_model_reviewer.py | 1 + .../configuration_data_processing.py | 11 +- .../example_models/T45/Graphics_Card.aedt | 1029 ++++++++++------- tests/system/extensions/load.json | 2 +- .../extensions/test_icepak_model_reviewer.py | 85 +- 5 files changed, 645 insertions(+), 483 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 2d02b9c149f2..787c5df744ee 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -212,6 +212,7 @@ def update_cell_value(self, row_id, col, new_value): self.rows_data[idx][col] = new_value def edit_cell(self, event): + region = self.tree.identify("region", event.x, event.y) if region != "cell": return diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index b54250270cb4..9be98ca91c52 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -50,7 +50,8 @@ def extract_boundary_data(data): if boundary_type == "Block": use_total_power = boundary_details.get("Use Total Power", "") use_external_conditions = boundary_details.get("Use External Conditions", "") - if use_total_power: + + if use_total_power and not use_external_conditions: bc_name1 = "Total Power" bc_name2 = "N/A" value2 = "0.0" @@ -62,7 +63,8 @@ def extract_boundary_data(data): ) cols.append(7) read_only_cols.append(cols) - elif use_external_conditions: + + if use_external_conditions: bc_name1 = "Heat Transfer Coefficient" bc_name2 = "Temperature" value1 = boundary_details.get("Heat Transfer Coefficient", "0w_per_m2k") @@ -73,7 +75,7 @@ def extract_boundary_data(data): [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] ) read_only_cols.append(cols) - else: + if not( use_external_conditions or use_total_power): bc_name1 = "Power Density" bc_name2 = "N/A" value2 = "0.0" @@ -275,6 +277,9 @@ def compare_and_update_boundary_data(original_data, modified_object_data, object updated_data["boundaries"][boundary_name]["Objects"] = selected_object_ids modified_boundary.add(boundary_name) + if bc_name1 == "Fixed Temperature": + bc_name1 = "Temperature" + if original_obj.get(bc_name1, "") != value1: differences.append( f"{boundary_name}: {bc_name1} changed from '{original_obj.get(bc_name1, '')}' to '{value1}'" diff --git a/tests/system/extensions/example_models/T45/Graphics_Card.aedt b/tests/system/extensions/example_models/T45/Graphics_Card.aedt index daec8388b4c7..43130353da7b 100644 --- a/tests/system/extensions/example_models/T45/Graphics_Card.aedt +++ b/tests/system/extensions/example_models/T45/Graphics_Card.aedt @@ -1340,7 +1340,7 @@ $begin 'AnsoftProject' SolveInside=true ShellElement=false ShellElementThickness='nan ' - ReferenceTemperature='nan ' + ReferenceTemperature='20cel' IsMaterialEditable=true IsSurfaceMaterialEditable=true UseMaterialAppearance=false @@ -1675,7 +1675,7 @@ $begin 'AnsoftProject' $end 'GeometryDependencies' $end 'GeometryCore' $begin 'AssignedEntities' - AssignedObject[7: 62, 90, 150, 178, 422, 554, 582] + AssignedObject[8: 62, 90, 134, 150, 178, 422, 554, 582] $begin 'AssignedFace' kID=10 $begin 'FaceData' @@ -1718,6 +1718,26 @@ $begin 'AnsoftProject' $end 'FaceGeomTopol' $end 'FaceData' $end 'AssignedFace' + $begin 'AssignedFace' + kID=120 + $begin 'FaceData' + ParentObjectID=118 + NormalValid=false + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=376.991118430775 + FcUVMid(-86, 13.6, -95) + $begin 'FcTolVts' + TolVt(-91, 1.6, -100, 5e-07) + TolVt(-81, 1.6, -100, 5e-07) + TolVt(-81, 25.6, -100, 5e-07) + TolVt(-91, 25.6, -100, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' $begin 'AssignedFace' kID=155 $begin 'FaceData' @@ -1738,6 +1758,26 @@ $begin 'AnsoftProject' $end 'FaceGeomTopol' $end 'FaceData' $end 'AssignedFace' + $begin 'AssignedFace' + kID=451 + $begin 'FaceData' + ParentObjectID=450 + NormalValid=false + $begin 'FaceGeomTopol' + FaceTopol(1, 4, 4, 4) + $begin 'FaceGeometry' + Area=17600 + FcUVMid(-80, 0, -55) + $begin 'FcTolVts' + TolVt(-160, 0, 0, 5e-07) + TolVt(-160, 0, -110, 5e-07) + TolVt(0, 0, -110, 5e-07) + TolVt(0, 0, 0, 5e-07) + $end 'FcTolVts' + $end 'FaceGeometry' + $end 'FaceGeomTopol' + $end 'FaceData' + $end 'AssignedFace' $begin 'AssignedFace' kID=455 $begin 'FaceData' @@ -1777,7 +1817,7 @@ $begin 'AnsoftProject' $begin 'GlobalBoundData' $end 'GlobalBoundData' $begin 'Boundaries' - NextUniqueID=6 + NextUniqueID=9 MoveBackwards=false $begin 'Grille1' ID=0 @@ -1846,6 +1886,53 @@ $begin 'AnsoftProject' Current='0A' Voltage='0V' $end 'Source1' + $begin 'Source2' + ID=6 + BoundType='Source' + IsComponent=false + Faces(451) + 'Thermal Condition'='Fixed Temperature' + 'Total Power'='0W' + 'Surface Heat'='0mW_per_m2' + Temperature='35cel' + $begin 'Radiation' + Radiate=false + $end 'Radiation' + 'Voltage/Current - Enabled'=false + 'Voltage/Current Option'='Current' + Current='0A' + Voltage='0V' + $end 'Source2' + $begin 'HTC' + ID=7 + BoundType='Block' + IsComponent=false + Objects(134) + ParentBndID=-1 + 'Block Type'='Solid' + 'Use External Conditions'=true + 'Use Total Power'=true + 'Heat Transfer Coefficient'='5w_per_m2kel' + Temperature='30cel' + 'Total Power'='0W' + $end 'HTC' + $begin 'Source3' + ID=8 + BoundType='Source' + IsComponent=false + Faces(120) + 'Thermal Condition'='Surface Flux' + 'Total Power'='0W' + 'Surface Heat'='5kW_per_m2' + Temperature='AmbientTemp' + $begin 'Radiation' + Radiate=false + $end 'Radiation' + 'Voltage/Current - Enabled'=false + 'Voltage/Current Option'='Current' + Current='0A' + Voltage='0V' + $end 'Source3' $end 'Boundaries' $begin 'ProductSpecificData' $end 'ProductSpecificData' @@ -2141,7 +2228,7 @@ $begin 'AnsoftProject' PlotDefinitionType='Mesh_field_type' PlotName='Temperature1' PlotDefinitionId=4 - VersionID=473 + VersionID=478 SolutionId=15 UserSpecifyName=0 UserSpecifyFolder=0 @@ -2199,7 +2286,7 @@ $begin 'AnsoftProject' MoveBackwards=false IDMap() $end 'QuantityIDs' - SimValue('Temperature', 1, 80, false, SimValueID=1083, 3, 0, 2, 0, false, false, 455, 1, 0, 1, 1, '', 0, 0) + SimValue('Temperature', 1, 80, false, SimValueID=1096, 3, 0, 2, 0, false, false, 455, 1, 0, 1, 1, '', 0, 0) $begin 'Sweeps' $begin 'Sweep' Variable='X' @@ -2215,7 +2302,7 @@ $begin 'AnsoftProject' $begin 'Setup' N='Setup1' V=1084 - Soln(N='SteadyState', V=1085) + Soln(N='SteadyState', V=1106) $end 'Setup' $end 'Version ID Map' $begin 'ID Map' @@ -2238,7 +2325,7 @@ $begin 'AnsoftProject' Notes=$begin_cdata$ $end_cdata$ $begin 'AnimationSetups' $end 'AnimationSetups' - CacheHeaderFile='HDR6EE53479217413415443.tmp' + CacheHeaderFile='HDR10587304817682362533.tmp' $end 'IcepakModel' $begin 'DataInstances' DesignEditor='TopLevel' @@ -2265,7 +2352,7 @@ $begin 'AnsoftProject' DesignInstanceID=1 $begin 'WindowPosition' $begin 'EditorWindow' - Circuit(Editor3d(View('View Orientation Gadget'=1, WindowPos(3, -1, -1, -9, -38, 200, 200, 992, 435), OrientationMatrix(0.00372929591685534, -0.00215311022475362, 0.0030449575278908, 0, 0.00372929591685534, 0.00215311022475362, -0.0030449575278908, 0, 0, 0.00430622044950724, 0.0030449575278908, 0, 0.246133506298065, 0.0344497710466385, -5.28414821624756, 1, 0, -1.55345916748047, 1.55345916748047, -1, 1, 0.520563125610352, 10.9551305770874), Drawings[12: 'Region', 'SERIAL_PORT', 'MEMORY1', 'MEMORY1_1', 'CAPACITOR', 'CAPACITOR_1', 'KB', 'HEAT_SINK', 'CPU', 'ALPHA_MAIN_PCB', 'Box1', 'MeshRegion2_SubRegion'], 'View Data'('Render Mode'=1, 'Show Ruler'=1, 'Coordinate Systems View Mode'=0, 'CS Triad View Mode'=0, 'Render Facets'=1, GridVisible=1, GridAutoAdjust=1, GridAutoExtents=1, GridType='Rect', GridStyle='Line', NumPixels=30, dXForGrid=20, dYForGrid=20, dZForGrid=20, dRForGrid=20, dThetaForGrid=10), ClipPlanes(ClipPlaneOptions(DisableWhenDrawingNewPlane=true, ForceOpqaueForUnclipped=false, ShowClipped=false, Transparency=0, HandleColor=16776960))))) + Circuit(Editor3d(View('View Orientation Gadget'=1, WindowPos(3, -1, -1, -9, -38, 200, 200, 992, 435), OrientationMatrix(0.00482711428776383, 0.000934596173465252, 0.00190808321349323, 0, -0.00209140800870955, 0.00292510259896517, 0.0038581220433116, 0, -0.000374592666048557, -0.00428784778341651, 0.00304785394109786, 0, 0.394846260547638, -0.202015370130539, -5.47158145904541, 1, 0, -1.45722711086273, 1.45722711086273, -1, 1, 0.520564079284668, 10.9551286697388), Drawings[12: 'Region', 'SERIAL_PORT', 'MEMORY1', 'MEMORY1_1', 'CAPACITOR', 'CAPACITOR_1', 'KB', 'HEAT_SINK', 'CPU', 'ALPHA_MAIN_PCB', 'Box1', 'MeshRegion2_SubRegion'], 'View Data'('Render Mode'=1, 'Show Ruler'=1, 'Coordinate Systems View Mode'=0, 'CS Triad View Mode'=0, 'Render Facets'=1, GridVisible=1, GridAutoAdjust=1, GridAutoExtents=1, GridType='Rect', GridStyle='Line', NumPixels=30, dXForGrid=20, dYForGrid=20, dZForGrid=20, dRForGrid=20, dThetaForGrid=10), ClipPlanes(ClipPlaneOptions(DisableWhenDrawingNewPlane=true, ForceOpqaueForUnclipped=false, ShowClipped=false, Transparency=0, HandleColor=16776960))))) $end 'EditorWindow' $end 'WindowPosition' $begin 'ReportSetup' @@ -2322,7 +2409,7 @@ $begin 'Design_0.setup/NativeGeometryFiles' NumFiles= 9 $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000034.x_b -BIN000000008453 +BIN000000008455 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2337,8 +2424,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000034.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2354,7 +2441,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block Q8-vQjpS???Q8p9Qk9S???S???R*R+R,OSDL/TYSA_COLOURQd~Q}z8{R0Qc{}R1Qb`S???Qa4S???Q` 2S???Q2w8 Q_S???n+++1Qv82Q^+S???+ nŽS +1Qu8+Q]S???n+]++1Qt8Q\S???n‘k+k1Qs8Q[kS???kn“)e+)1Qr8kQZ)S???)!nk<,-k1Qq8)S???Qp8R(QnQ&R"P(#Q&RT SERIAL_PORTOAEDT_BODYFlagGroupColor_V1PQQmT SERIAL_PORTP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAME2,)) + rh?ʡEͿ?? 1 )2(k,+{GzMb?{Gz2'+{GzI +?Eؿ??2&+{GzI +?{Gz??2%+{Gz rh?ʡEͿ??R'R&R%R$R#R4S???S???OAEDT_EntityID_V1R)R2R3Rw-QM8B:iQI8GiORj9R8Q:8/6MR:R;Rd6R\5RR7R;<*# SJ([&P%8(#T 'Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000062.x_b -BIN000000008450 +BIN000000008452 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2369,8 +2456,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000062.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2386,7 +2473,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block +ܿMb?Q??2%t+gfffffֿMb?Q??RBRAR@R?RPRORNS???S???OAEDT_EntityID_V1Q9/HQH9FPRRQP9JTHRQRSRMRyGR\TQL9B;RRUUQ;976LRVRWR<X+# SJ)'P&9(#T(Ceramic_materialOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000090.x_b -BIN000000008454 +BIN000000008456 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2401,8 +2488,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000090.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2418,7 +2505,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block +?@[\]^_`{|}~0123456789************************** **PART1; @@ -2433,8 +2520,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000118.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2450,7 +2537,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block +[W2QnE:,pilqP:rs(#Qp6t,numvQiD:WuenwRqxQu5tWigpxRwyPtyAQg4t*euzSx???Sz???OySDL/TYSA_COLOURQm7t[lp{|Sv???Q{8t3m}~S|???Q3G:{lTQ}9t5T{cS~???QTH:5}3aQc:t.a}`S???Q`;tK_cS???Q<tVY`]S???QYK:V_;Q]=tS;S???S???R|RROsAEDT_EntityID_V1RowQhB:eRjzQ@hQQrh'RvPr(#Q'RRT CAPACITOROAEDT_BODYFlagGroupColor_V1PQQ?T CAPACITORP(#Q3RPthS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMERd~Rb}U56+QMb?R^{@HEA84?-RNQ<N:87DRGRR=+ SJ)]F'P&:(#T(Ceramic_materialOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000134.x_b -BIN000000006226 +BIN000000006228 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2465,8 +2552,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000134.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2482,7 +2569,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block +Mb?S???>?{?>448QTJ+JOQP8EK+S~???Sx???St???Sp???Sm???/#T6 +Mb???6"V/+Mb??V!5Z6+gfffffMb?Z WhV+Mb??hKZ+Mb?Sj???Se???Sa???O^AEDT_EntityID_V1@HEA84?-RNQ<N:87DRGRR=+ SJ)[F'P&:(#T(Ceramic_materialOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000150.x_b -BIN000000008435 +BIN000000008437 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2497,8 +2584,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000150.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2526,7 +2613,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block ףpS???S???S???S???S???S???S???QG7FHRR?>@MVR+RRnQ9705HRJRR:+# SJ)'P&7(#T (Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000178.x_b -BIN000000051253 +BIN000000051255 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2541,8 +2628,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000178.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2590,7 +2677,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block  'P&;e(#T (Al-ExtrudedOeAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000422.x_b -BIN000000008437 +BIN000000008439 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2605,8 +2692,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000422.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2622,7 +2709,7 @@ notransmitlCCCDCCDI finger_indexdI finger_block +Gz׿Mb?Qۿ??nn ,-n1Qv92n n…ik +i1Qu9ninna +n12%n+(\Mb?HzGѿ??2&+(\Mb?zG?Qt9iQ]iQs9RQ\RPAQ[\S???QZ*S???S???OSDL/TYSA_COLOURQ^nS???Q_S???Q`2S???Q2w9Qa4S???Qb-S???QcdS???QdZc}S???Qc{9Z|Q}ee|S???Qfhl}tS???Ql}9h|rQtg_rS???QhputS???Qu9prQiwS???QjzS???Q9z:Qk:S???:n€zQ:96S???R7m+(\Mb?zG?m6hx+(\aÙ?HzGѿ?x5p5m+(\Mb?HzGѿ?54fx+zGʿMb?zG?f3Z5+zGʿaÙ?HzGѿRRRRRRRRQp9RQnQ'RP(#Q'RTCPUOAEDT_BODYFlagGroupColor_V1PQQmTCPUP(#QYRPhS???OSDL/TYSA_COLOUR_2OAttGS_PS_LayerO SDL/TYSA_NAMERRRRR~RvQP9B;URWQ;986PRRR<+# SJ)'P&9(#T (Al-ExtrudedOAEDT_MaterialName_V1$end 'x_b' $begin 'x_b' Design_0.setup/NativeGeometryFiles/0000450.x_b -BIN000000008459 +BIN000000008461 **ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz************************** **PARASOLID !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~0123456789************************** **PART1; @@ -2637,8 +2724,8 @@ SITE=unknown; USER=unknown; FORMAT=binary; GUISE=transmit; -KEY=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; -FILE=C:/Users/skrishna/AppData/Local/Temp/Gra0F28101217539472302.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; +KEY=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; +FILE=C:/Users/skrishna/AppData/Local/Temp/Gra11057304817682363064.setup/Design_0.setup/NativeGeometryFiles/0000450.x_b; DATE=unknown; **PART2; SCH=SCH_3601185_36001; @@ -2668,126 +2755,144 @@ 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' $begin 'DesignInfo' DesignName='IcepakDesign1' Notes='' @@ -2807,292 +2912,332 @@ LDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAA\ AECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB\ CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ\ 3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4u\ -Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigAooooAKKK8A+On7UfwJ/Zw/wCEWsvix\ -45/s7xb4+/tv/hWnwp8H+GfGPxX+O3xZ/4RX+yJfGX/AAp39n/4T+Htb8bfF7+wdM1zTdS8Q/8ACM6B\ -qv8AYGjvLres/YdItrm9iAPf6K/GH9rvxz/wUVuvhT4T+KI+JPh/9g/wt4g/af8A2IvhHoXw1+E+h/C\ -/4/8A7Ss/hX9pb9tD4Bfs+6/rfxh+Lnxf8E+Ifhv4E8QQfC743+KkvfAXhDwX41ttF8b/AA/0bW9K+O\ -fjDwpPqXhnUfp//hpD42fsyf6P+3do/wAP7/4ZP+50z9sf9nDwR8XYPhZp11F/xONdu/2nPgVqEfi/U\ -P2LPh/pnh+7vHXx7qPj/wAc/Dgad8M/EHiHx94w+FU+o+FvCurgH3/RXP8AhPxZ4V8e+FfDPjrwL4m8\ -P+NPBPjTw/o3izwd4x8J6zp3iPwr4s8K+I9OttY8PeJvDPiHR7ma017w/f6ReWd1ZXtrNLbXVtdRzwS\ -PE6segoAKKKKACiiigAooooAKKKKACivym/4KrfFX4g2ng79nr9k/4I+PvFHw1+Nv7afx88HfC7RPHX\ -gXWNQ0Lxt8P/hf4Y1HT/F/xk+Ivh3VNJu4Lm1m03w9babbTmGRHa28RTBXU81xH7BP7Y/jiH/gnf8AG\ -jxJ8ZX1H4h/tCfsAW3x8+F3xx07XfEV5F4g8beK/wBnbS9c1rSrrVvE2qWt9dm61nwtYaNDcaxcwXss\ -+ow39063MqSRkA/ZCivw2+BP/BZLxb8T/HX7I1j8R/2IviJ8Ffg9+2dcHw18IfjPqnxS8KeLLTUviBb\ -WEf2/Rh4L0zw/bX1v4VbX5Ba6fq9/Jp8+pWkianBpK2/nJBoaT/wWM1nxX+0T40+Ffw//AGNfiR8Rfh\ -Z8Ofj1qv7P3jf4j+CPiT4L8TfF3RPEOg6y2g654w/4ZN0SxufGN18OLW8juJ5NYUC3WytpHfZexyWCA\ -H7c0V+WPij/AIKd6H8OfEP/AAUW8K/FH4V/8IXrv7BngzQPiLotr/wny6lH8e/BfjXw7e6t4G1PRJ5f\ -BlqPB93e62fDmkXMONXjsb7xPDGbi4aKRK8G+K3/AAWG8dfD/V/gX8O/D/7Gl34x+OHxU/Zo8J/tP+L\ -fhnqn7Rvw9+GVv4J8J+MZ7uLT/CHhLxF8QvDdlN8YPiPCtlcC40bSdLhvGlBgs4rt4ro24B+49FeY/B\ -f4lP8AGL4U+A/ifL4G8e/DO48a+HLHW7v4f/FDw1qPg/x/4Pvp1ZL7w/4o8ParBHNY6jbXkU8e7b5Vx\ -GqXNu0lvNFIxQB6dRRRQAV5/wDFL4sfCz4HeBNd+KXxr+Jfw/8Ag/8ADLwv/Zn/AAk3xF+KXjLw58P/\ -AAJ4d/tvWNP8O6N/bvi7xZqVpp+kfa/EGr6VY2v2i4j+0Xmp29rFvnmjRvQK/EHTLP8Aan8X/t7ftnf\ -tC6J4c+H/AO1F4M/ZB/aA8E/AT4Sfs5eK/GvxF+F3jv4W+HNZ/YP/AGWfjj49+KX7PGpal4/vvhF4s/\ -aAvZv2ivjD4b0WPxZ4E8E+KtSs/jJqug6z+0j4X+HMS+EwAfX/APwsv9qf9qj/AJN303/hlf8AZ/vv9\ -Auv2g/j78J/iLpX7U/ivyf+JZ4ws/gr+x38YvBvhz/hS/kf2rcf8I58Qvit/a2zxH8Orz7R8AfGnw/1\ -nw94w1n6A+Bf7NHws+AP/CU674W0n/hIPi18Tf7EvPjp+0J4wsPDl78dv2g/Efh/+120jxH8YvHeiaD\ -p/wDwkH9n/wDCQa3b+HtEs7XT/CvgvR72Lwt4F0Dwx4S0/S9BsT4F/tR/An9o/wD4Smy+E/jn+0fFvg\ -H+xP8AhZfwp8YeGfGPwo+O3wm/4Sr+15fBv/C4v2f/AIseHtE8bfCH+3tM0PUtS8Pf8JNoGlf2/o6Ra\ -3o327SLm2vZff6APgD/AIKWf8m6/Dn/ALP/AP8Agk7/AOvTf2N6+/6+AP8AgpZ/ybr8Of8As/8A/wCC\ -Tv8A69N/Y3r7/oA+IPFn7Huo+D/FXib4n/sV/Ejw/wDsk/ETxz4g1nxn8U/CEPwc8K/EX9l/9oH4heJ\ -NRubjWvip8fvghpOq+Fdb1b4wG21nxDLJ4v8ABHjvwB4m8R6hF4eHxG1Xx54d8I+H/DNmeE/2ztO8Je\ -KvDPwg/bK8NeH/ANlP44+L/EGjeGPA5m8W+KvG37MHxl8QeM9RtrD4eeD/AIA/taeLfhX4M0Tx/wDGD\ -Vrm4v7CP4a6tpvhj4oSah4J8Q3+leCtX8D22i+N/EH2/XP+LPCfhXx74V8TeBfHXhnw/wCNPBPjTw/r\ -PhPxj4O8WaNp3iPwr4s8K+I9OudH8Q+GfE3h7WLaa017w/f6ReXlre2V1DLbXVtdSQTxvE7KQDoKK+A\ -P+FJftHfsw/8AE/8A2cPiv8QP2hvg/ov/ABMNd/ZI/aP8VXXxY+Kd3o9t+91PTP2Y/wBsf4peObTxPp\ -HxAu73V/FWuNY/G7XfiRoWvajp/h/wNonin4H+DxceINL9g+Cn7Xnwa+NnirUPhZa3viD4YftB+HvD9\ -14n8Y/sx/GvQZ/hp8ffDXh/SdR0rw74h8Yaf4J1iUxfFT4P2XjbVl8PxfErwJe+K/hfrmtafd2nhfxr\ -rqwNLQB9P0UUUAFFFFABRRRQB+P37R//AATB0/8Aba/bhf4u/teWHgz4g/sn+APgTb/D34L/AAl0Tx7\ -8UfDfjFfiTqviPT/EPirx/wCMW8KQaMmmxGE6lp8MNlrl6t3BYabNcwQyQtGPLfBP/BJzxR+zl45/bi\ -8Hfso3Xw38E/sl/tc/sia58MdK+GXijx38UdX8S+Bv2g/+ES8ReEvD/ib7Vr2ha7Jd/D+a28Sa3NqFw\ -+sT6jHLrrJbac9tYWsEnVftXfHLwtZ/8FEf2dfgj4F/af8AFXgT4xXXin4PeKPiF4X8XfH/AEj4c/Af\ -wt8H7PxJqCaj8NdG+Etxe2MPxt+OfxNl1ez0iy0+4g17VtLgFjq9hLokEUS3/wAxfBX9ovxfBrv7Q+p\ -/Hv8AaR+OXgrwzo/7PH7XniX9sDUNK8X6peaz+zd8TPDH7Xd14M+A2kfC/QPEem6nY/CDxbqHwMk1uL\ -QtL0nTrc63aWWm63Hb3N9JbahKAfT6f8E4/jcvwv8A+CSXgn/hKPhV/av7BXxA8F+K/jBcDW/Fv9n+J\ -NP8O6Laadfw/DaX/hBvM1i9e4gdol1SLR0ZSC8iNlR8yftPf8EgP2sf2jfjP4k1LV/iR+x8fCOu/Fyw\ -+IOh/tR2/wAHtV+HP7dHw+8N2Gs2Gp6b4P0zVfhDpGjeGvG11p9lZLZ2+r620upzgC4a4tW8mG35a1+\ -MHinx7+xh4F8d2P7bWhfDH4d+Kv2xfiF4v0C58Z/tLfHj4q+IvA3wmsfgN4j1X4cfsr/Gf9of9nX4pW\ -Gtad8Q9R8RzaV4ludK1r4haVd2kniDT9BtrvWb20tNDv8A7f8A2p/iJ8V9W/4Jpfs0eK/Dmn/Eb4Q/E\ -f4j+Lf2EdC1Xwbc/Gz4u+BPHWnL8RfiZ8LNC8SfDrxb8dNMurvxtpv22y1e70zV9cnN94iMV5PeXsN3\ -qXmxOAfnb/wUU+GPgf8Aba/4KrfAz9nr4Ha94s1PxJJ4X0z4W/8ABRDRrbwb4q0fwrpvwF+HXj7wB+0\ -J4St/EnijUtEgsNXv9Snt5YbK4s5LmI3i6NZNcgubav0N/wCCjH7Bn7SH7UXjbRNZ+F837GXxJ+HKeA\ -5vBsvwk/a/+EFzex/DnWZrxpLj4gfCP4t/Cjw/F4v0zU57H7LG+lXOqLpSS2Pn+XN5scdn8VeK/HX7T\ -Wk/sT/8FMRp3x8+J/wA+JfwF+Jcd1qHwW1P4pfEb4//ABV+Dfgqy8C+HotDsPBX7T3xT1aDxJqXgzx3\ -qUMvifTdeFs722nTXmkaWNPvVu57T9oP2vvib8ItK+Fnj3w74u+Ot58ML7wzL8OtT8Uv4K+J2sfDfX9\ -Ct/FviW4tfh/ZfFD4g+BPDes698CPhF4n8Q6BfaTqXjCO1082OnwalPaarbSWsrqAaH7Cf7N2vfsh/s\ -m/Bj9nTxP8QLv4oa78MvD+o6bqPjK6S6iivJtW8R614jGlaTDfXEs0Ph3TItZj0zTElfcun6PbL5cIA\ -hjK5n/gnH408a/ED9iz4GeJ/iJ4g8TeLfGNxo3iXTNY8VeKxLNqPiX/AIR3xz4o8PafrthrFzI0/i7w\ -tdaXpdlLouv3Wy88Q6PJY65eRQ3OoSxIUAfblFFFABXwB+xv/wAnFf8ABWL/ALP/APhx/wCusv8Agmn\ -X3/XwB+xv/wAnFf8ABWL/ALP/APhx/wCusv8AgmnQB9AfHT9mj4WfH7/hFtd8U6T/AMI/8Wvhl/bd58\ -C/2hPB9h4csvjt+z54j8Qf2Q2r+I/g7471vQdQ/wCEf/tD/hH9Et/EOiXlrqHhXxpo9lL4W8daB4n8J\ -ahqmg33z/8A8LL/AGp/2V/+TiNN/wCGqP2f7H/QLX9oP4BfCf4i6r+1P4U87/iWeD7P41fsd/B3wb4j\ -/wCF0ef/AGVb/wDCR/EL4U/2Tv8AEfxFs/s/wB8F/D/RvEPjDRvv+igD8wP22vix8LPjj+x18HPil8F\ -PiX8P/jB8MvFH7f8A/wAEsP8AhGfiL8LfGXhz4geBPEX9if8ABWb9kfw7rP8AYXi7wnqV3p+r/ZPEGk\ -arY3X2e4k+z3mmXFrLsnhkRf0/r8Yf+CrH7L/hWLwD4e/aF+CD+H/gf+0j4q/bf/4JbaV40+Iej+C9O\ -1Twr8eJ4f8AgoX+x/4M+GNr+1h4H0q+0e7+PPh/wfq9p4Q1Pw7cR6/4e8ZaHbeGLvw14Z8a+HvC/izx\ -rpHiL6f/AOG1v+Gf/wDilv2+tA/4Z/8A7F/4lv8Aw11/ZX9n/sJ/FD7J8v8AwmX/AAtP/hK9b/4Y/wD\ -tv9oeDbP/AIRn41X3hfzfGPjX/hBfhx4s+MH9mf8ACVamAff9FFFABXj/AMa/gR8M/wBoPwrp/hL4m6\ -X4gnttD8QWvizwr4l8DeP/AIhfCH4meA/FVrp2q6EfE3w2+L/wi8U6F4r+GniC48LeIfFGh317oGtad\ -c6j4e8Y634ev5LnRNa1WwvPYKKAPgD+3f2sf2Tv9I+IeofED9vb4Cn93P458G/C34baF+2T8HbW1/4n\ -niLxv8WfBPw61Pwz4Y/aq+H62U/iZLaz+EvgDw38R9Hg8KeGfD2jfDf4ya74l1fxJoP1/wDC34peBPj\ -R4E0L4k/DbXf+Eg8JeIP7TgtrmfTNY8P6xpWseH9Y1Dwz4s8I+LvCfibT7PV/AnxA0Lxbo+uaJ4j8Oa\ -3Y6frvhzXfD+o6Hrmnafq+n3tlB6BXyB8Uv2KfhZ458d678afhzr/xA/Zd/aN8S/2Z/wAJN+0P+zVqv\ -hzwZ478e/2No+n+FNG/4Xd4L8WeFNe8BftPf2X4FtL7Q/DX/C0/Bvjb/hCrPxBf3fgj/hG9Zlj1WEA+\ -v6K+AP8AhrL4p/s+/wDEs/bn+EP/AAh3hKw/cf8ADYvwCt/EfxK/ZYvLG1/0f/hKvjV4Y+yTeNv2LvM\ -0zRfF3inxHc+KbHxL8Gvhz4ctbO31v9oXWdXn8k/f9ABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABXwB\ -+xv/ycV/wVi/7P/wDhx/66y/4Jp19/18Afsb/8nFf8FYv+z/8A4cf+usv+CadAH3/RRRQB8Af8FLP+T\ -dfhz/2f/wD8Enf/AF6b+xvX3/XwB/wUs/5N1+HP/Z//APwSd/8AXpv7G9ff9AHwB/wyb8U/2ff+Jn+w\ -x8Xv+EO8JWH7/wD4Y6+Ptx4j+JX7LF5Y2v8ApH/CK/BXxP8Aa5vG37F3maZovhHwt4ctvC194l+DXw5\ -8OWt5caJ+z1rOrz+cfYPgp+1T4V+LnirUPhd4l+HXxg/Z6+O2j+H7rxZqnwM+PnhHTtA8VXPhWy1HSr\ -G+8TfD34g+BfEXiL4e/Hzw/YR+KfAD+IL34ceNPGFt4OufiZ4d0TxrJ4c8S6pDoo8C+H//AAVV/Y++K\ -2l+IW+HHiTx/wCL/Geh3fkWnwp034V+Obf4keJLHVLnXU8D+KdH0zVNIt7Gw8AeINP0rSL628SavqOm\ -aBoVt478PL401Lwvd6rBaj3PV/D37Lf7enwwtYfEvhbSvil4W8LeNf7W0QeKvDHi3wB8Uvgp8XtA0a6\ -g0Lx34QfXtO0Xxr+zp8ddK0DxcupeGfE+lnw94s0m08U2HiDw5qVtDf2GoTAH1TRXwB/YX7WP7J3+j/\ -DzT/iB+3t8BT+8g8DeMvil8NtC/bJ+Dtra/wDEj8O+CPhP42+IumeGfDH7VXw/Wyn8Mvc3nxa8f+G/i\ -Po8HhTxN4h1n4kfGTXfEukeG9B+n/gp8d/hn+0H4V1Dxb8MtU8QT22h+ILrwn4q8NeOfAHxC+EPxM8B\ -+KrXTtK10eGfiT8IPi74W0LxX8NPEFx4W8Q+F9csbLX9F0651Hw94x0TxDYR3Oia1pV/eAHsFFFFABX\ -wB/wxT/wz/wD8VT+wLr//AAz/AP2L/wATL/hkX+1f7P8A2E/ih9k+b/hDf+FWf8Iprf8Awx/9t/tDxl\ -ef8JN8FbHwv5vjHxr/AMJ18R/Cfxg/sz/hFdT+/wCigD5A+Fv7XOj6z470L4EftB+EP+GW/wBprxH/A\ -GnH4G+Enj3x74E1/R/2hLXwto+oal428b/sjePdD1df+F7/AA/03+wPEN1eWd1pXhn4j+HdCj0fxB8Q\ -/hv4EsvFHhtdU+v68/8Ail8J/hZ8cfAmu/C341/DT4f/ABg+GXij+zP+Em+HXxS8G+HPiB4E8Rf2JrG\ -n+ItG/t3wj4s0270/V/sniDSNKvrX7RbyfZ7zTLe6i2TwxuvyB/wrT9qf9lf/AJN31L/hqj9n+x/0+6\ -/Z8+PvxY+Iuq/tT+FPO/4mfjC8+Cv7Ynxi8ZeI/wDhdHn/ANlXH/COfD34rf2Tv8R/EW8+0fH7wX8P9\ -G8PeD9GAPv+ivAPgX+0v8LPj9/wlOheFtW/4R/4tfDL+xLP46fs9+ML/wAOWXx2/Z88R+IP7XXSPDnx\ -i8CaJr2of8I//aH/AAj+t3Hh7W7O61Dwr400eyi8U+Bdf8T+EtQ0vXr73+gAooooAKKKKACiiigAooo\ -oAK+AP2N/+Tiv+CsX/Z//AMOP/XWX/BNOvv8Ar4A/Y3/5OK/4Kxf9n/8Aw4/9dZf8E06APv8AooooA+\ -AP+Cln/Juvw5/7P/8A+CTv/r039jevv+vgD/gpZ/ybr8Of+z//APgk7/69N/Y3r7/oA/i1+G/w88N+I\ -vgZ8CWu9Ci1fVdC8JfDXX9A1u98R+INJ8T+Fb24HhjxDqWseEfHGnPLq/hnULaW0Seyg0+5tIj/AGVa\ -aYstlYKjW9rwN8Wf2kPB2vfs+/Gyz1/xJ8VfBPhrxN8HPHGqeN/Ctrpfgv8Aa/1L9nzQ9c0nxjrvwD8\ -b65pOq2lp8dPh3d+FLK7lvNFu7+O98QeL9Ztr+7kmtrQxS9b8B76yu/g38Lre1vLW5n0v4cfDyx1KG3\ -uIZptOvZPA3h3Uo7O+jjctaXTadqOn3AjkCuYL6GUDy5UZrXwP/wCSK/CD/sl3w/8A/UT0mgD+qD4B/\ -tE/Bb9qH4e23xU+A3j/AEr4ieBrjVdU0J9W0621XTLvTtb0eVE1DRtd8P8AiDT7TUvDuqrDPZXKW9/a\ -W001jqdnqEKSWN7aXE3E/Gv9kP4NfGzxVp/xTurLxB8MP2g/D3h+18MeDv2nPgpr0/w0+Pvhrw/pOo6\ -r4i8PeD9Q8baPEYvip8H7LxtqzeIJfhr47svFfwv1zWtPtLvxR4K11YFir+bZ/DGo6H4qf4nfCnxZ4g\ -+DXxngtYoNP+Kfw/u5tJ1i7S01Hw5q9rpHjzSLeaOx+Kngt77wl4eS70LxDDf6ddWlibYRw7xIv6f/A\ -AZ/4KzS6J4j8PeAf2yPAWleAI/EWqrpelftH/DH+05fgHbSajr2uWWlf8La0jxTfS6l8Bx5M/gKwW6m\ -1PxNpFzfeILq9udV0jTbG7a1APqr/henx2/ZX/4lP7WPhb/hY37P/h7/AEX/AIb08E634Otv+EU8HWP\ -H/Cwv25/gl/ZHhz/hS/kf2r4csNX8Y/DSDxp4Ef8AsLxT8TPGWj/AH4f2v9kaN9v+E/FnhXx74V8M+O\ -vAvibw/wCNPBPjTw/o3izwd4x8J6zp3iPwr4s8K+I9OttY8PeJvDPiHR7ma017w/f6ReWd1ZXtrNLbX\ -VtdRzwSPE6sbeha7onijRNG8TeGdZ0rxF4b8RaVp2u+H/EGhajaavomu6Jq9pDqGk6zo2rafNJBqelX\ -VhcW89vcQSPDPDOksbsjKx/MX9pjwP8As2/sh68/xu+Fv7RHwc/4J9fGr4u+Nr28v4/GMOr63+zZ+0L\ -4s8e+L9G0v4l+N/jR+x14b+LfgzTPib8SZ9Z8Z+EdT134s6LfeGviDox8L+H5fF3j25+Glh4h8J63hi\ -cThsHQqYnGYiGFw1FXnUqTjCEVdK8pyajFXaV21q0j1MlyTOuJM0weR8O5Ris+zrMJOGHweCw9XFYqv\ -NRc3Gjh6EKlWrJQjKTjCEmoxcrWTZ+p9FfEHhP9sLUfB/irwz8MP21Phv4f/ZJ+InjnxBo3gz4WeL5v\ -jH4V+Iv7L/7QPxC8SajbW+i/Cv4A/G/VtK8K63q3xgNtrPh6KPwh438CeAPE3iPUIvEJ+HOlePPDvhH\ -xB4ms/t+tzywooooA8A+On7NHws+P3/CLa74p0n/hH/i18Mv7bvPgX+0J4PsPDll8dv2fPEfiD+yG1f\ -xH8HfHet6DqH/CP/2h/wAI/olv4h0S8tdQ8K+NNHspfC3jrQPE/hLUNU0G++f/APhZf7U/7K//ACcRp\ -v8Aw1R+z/Y/6Ba/tB/AL4T/ABF1X9qfwp53/Es8H2fxq/Y7+Dvg3xH/AMLo8/8Asq3/AOEj+IXwp/sn\ -f4j+Itn9n+APgv4f6N4h8YaN9/0UAef/AAt+LHws+OPgTQvil8FPiX8P/jB8MvFH9p/8Iz8Rfhb4y8O\ -fEDwJ4i/sTWNQ8O6z/YXi7wnqV3p+r/ZPEGkarY3X2e4k+z3mmXFrLsnhkRfQK+QPil+yNo+s+O9d+O\ -/7Pni//hlv9prxH/Zknjn4t+AvAXgTX9H/AGhLXwto+n6b4J8Eftc+Atc0hf8Ahe/w/wBN/sDw9a2d5\ -a6r4Z+I/h3Qo9Y8P/Dz4keBLLxR4kbVPP8Awf8Ati6x8NPjt8Hf2PP2z7P4f+Bv2jf2hf8AhYQ/Zd8T\ -fB248d+LPhZ+1Ro/wV8HXXiz4ua/a6Nqnhg6h+zJ8QNI8P6dba9rHgvxPqevaFp+nfEHw9pfhL4q/Ez\ -WYfEseggH3/RRRQAUUUUAFFFFABXwB+xv/wAnFf8ABWL/ALP/APhx/wCusv8AgmnX3/XwB+xv/wAnFf\ -8ABWL/ALP/APhx/wCusv8AgmnQB9/0UUUAfAH/AAUs/wCTdfhz/wBn/wD/AASd/wDXpv7G9ff9fAH/A\ -AUs/wCTdfhz/wBn/wD/AASd/wDXpv7G9ff9AH8e3wP/AOSK/CD/ALJd8P8A/wBRPSa7Pwr4dsvCHhfw\ -34T02W6n07wvoOj+HdPmvnhlvZrLRNPt9NtZbyS3gijkumgtozIyRxoXJKoi4UcZ8D/+SK/CD/sl3w/\ -/APUT0mvUaACqmoahYaTYX2q6rfWemaXplnc6hqWpahcw2Vhp9hZQvc3l9fXly6x2lnFbxySSyyMqRp\ -GzMwUE1bryP9oD/kg/xs/7JH8SP/UN1quPMcTLBZfjsZCKnLCUatVRezdOEpJO2tm1Zn0nBuR0uJ+L+\ -FeG69eWFocQ5lgcDOrBJzpwxeKpYeVSKlo5QVRyino2knoL8DPHvxI+H2ial8Vv2H/i9efCXSvH3h7x\ -raW3w/u7TSvE3wE13VdR0e88I6f8SIvhbHPNp/g74lxX3h3wVe2+qrbm9s18Kx6X4k8PXQuNf0K59e8\ -N/HDT/i78RNb+FWoNY/sPeJLbx58M/Hfgu61rUtX+N3jr9qr4m/CHxd4X8TfBLW/iX+138bNY/tj9pj\ -w74Z8c3ml/2d8P7q10vWLOwv8AStN0/Wlt9PudN0fzfXvh5bXOq3XivwhqP/CCeOL3yDqviHSdJ0q7t\ -vGEdhbQwaZpfxD0m6tx/wAJXpEP2Szjjkjnsdas7Rbm00fWtKiv70z8prXivTbDTLnw1+0HofhS10K8\ -8kf8JVcWV1q/wk162sbiJobvxTda/pbWnwy1dtWt7GWHTNaup7Qz6rp9po+v69qCXaWnkVHQgqS4iwt\ -OU6MHT+tyjH6tLmjyTfvN/VHXTtOnUtCTlCgq+Iahf76jhcyx/wBe/wCIO55jqOEzHFU8Z/q9h8RiKe\ -eUJYevHEYOF8NGj/rDHKqkI1cJi8JzYqj7GvmtTKsojKvy/qZJ4p8AfCvw1rHgLxx4Z8GfAPwd4p8P6\ -n4X8RfDi6s77xZ/wSs+P/hbWorDwXrfgH4seBvE/gbWLf8AYO/4SZ/FHi6S5t9DitfDMmpfEGDVfFOs\ -/Gq9stR8NSer+BrD4t/s6+KdL+Gf7Ntt8P8A4N6/rn259K/4J8ftdfGHxpf/AAb+Jr+HtOvLS51z/gn\ -D+1B4b1TxbqH7P/wS8P8Ah+0u5Lr4c2nwy17StG8M/DDwfaWHwc+AKeLb/wAUeJfyp8F/EX4+/s4aLp\ -+k/DKWH44/DHQ4bPS9I+C/j/VbPQ/FfhnRUl8RfZtO+HXxikj3RaLZSar4dij07xNaa00OkeF/sWm6l\ -Zt5MDfT3wh8e/Cz4maNe+CPgPrngm68Di00HVvij/wTr/aK+HWit8Kriz0oab4wuLeL4ReJPD76j8FN\ -Vk8UeJvCU8nijwxDrXgpNdjbW5PDXirWZbi4uez+zqmDfPlNRYamrP6s0lhn3UYpXw7l/NR9xSlKrOj\ -Xm+V/N/65UeIH7Dj/AAtTPq1a0f7ZhNvPKCfuxnVq1KkaWcU6K5bYfMmsTKhSp4HCZpl2HjTdP9nvgp\ -+158GvjZ4q1D4WWt74g+GH7Qfh7w/deJ/GP7Mfxr0Gf4afH3w14f0nUdK8O+IfGGn+CdYlMXxU+D9l4\ -21ZfD8XxK8CXviv4X65rWn3dp4X8a66sDS19P1/N345/aY+D/ijwRr/AMMPiV8F/G3xyg/Z7s9H+OXx\ -V/ZS+Lk3xM+Jf7TH7G2p6P4EPi/xj+07+zr/AMFG7HxFrOnWmu+GPAuseL9Y8ATa34l8G/EddX8Q3kH\ -hL4j+FruHwn8Pbf8AUX7Z+2T+y3/xMPGHiP8A4bn/AGeNJ/0zxT4u/wCEKsfBn7dnw48ORfv9b8R/8K\ -6+BfgCHwT+2j5ep61dXX9ieDvC3wi8VaH4O+H32Hw9oHxv+ImqWenalWXZth8wq4zCxtHG5c4xrwi+e\ -EJSc4rlqxXLJN052i+StGKi61Gk5Ri44v4BzbhPL+H8/qqVfhni+NapleJq0pYTEV6VGGFqz9tgKz+s\ -UJQpY3Ct1ofWMuxE5z/s3McwpUalZff9ef8AxS+LHws+B3gTXfil8a/iX8P/AIP/AAy8L/2Z/wAJN8R\ -fil4y8OfD/wACeHf7b1jT/Dujf274u8WalaafpH2vxBq+lWNr9ouI/tF5qdvaxb55o0b5A/4a/wDGP7\ -Qn/FLfsKeBf+Ex1OL/AEfx/wDHT9ovwF8dvgx8Cfgp9q/4kl7YWOkeI/htpur/ALS/7QHh3xa2uWfiL\ -4U6BfeGv+Eb1j4TeLvAvxW+Inwd8bQaJpesegfC39kbR9G8d6F8d/2g/F//AA1J+014c/tOTwN8W/Hv\ -gLwJoGj/ALPdr4p0fUNN8beCP2RvAWh6Q3/CiPh/qX9v+IbW8vLrVfE3xH8RaFJo/h/4h/Ejx3ZeF/D\ -baX6p8Ief/wDCy/2p/wBqj/k3fTf+GV/2f77/AEC6/aD+Pvwn+IulftT+K/J/4lnjCz+Cv7Hfxi8G+H\ -P+FL+R/atx/wAI58Qvit/a2zxH8Orz7R8AfGnw/wBZ8PeMNZ8A+Kv7LnwJ/Zw/aK/4JjXvwn8Df2d4t\ -8fft/8Aiv8A4WX8VvGHibxj8V/jt8Wf+EV/4JZf8FQ4vBv/AAuL9oD4s+Idb8bfF7+wdM13UtN8Pf8A\ -CTa/qv8AYGjyRaJo32HSLa2sov1+r4A/bI/5OK/4JO/9n/8AxH/9dZf8FLKAPv8AooooAKKKKACiiig\ -Ar4A/Y3/5OK/4Kxf9n/8Aw4/9dZf8E06+/wCvgD9jf/k4r/grF/2f/wDDj/11l/wTToA+/wCiivkD4p\ -ftc6Po3jvXfgR+z54Q/wCGpP2mvDn9mR+OfhJ4C8e+BNA0f9nu18U6Pp+peCfG/wC1z491zV2/4UR8P\ -9S/t/w9dWdna6V4m+I/iLQpNY8QfDz4b+O7Lwv4kXSwDz//AIKWf8m6/Dn/ALP/AP8Agk7/AOvTf2N6\ -+/6+AP8AhkDxj+0J/wAVT+3X46/4THU4v9I8AfAv9nTx78dvgx8Cfgp9q/4ndlf32r+HPiTpur/tL/t\ -AeHfFraHeeHfitr9j4a/4RvWPhN4R8dfCn4d/B3xtBreqawfY/wBsn9lv/iX+D/Dn/Dc/7PGk/wCh+F\ -vCP/Ca2Pgz9uz4ceHIv3GieHP+Fi/HTx/D4J/bR8vU9atbX+2/GPin4ReKtD8HfD77d4h1/wCN/wARN\ -UvNR1IA/n1+B/8AyRX4Qf8AZLvh/wD+onpNeo189/s3+PPD/iH4a+FPCVtJdWXiv4daFo/w48deG9Tt\ -mtdW8JfELwP4Q8ET+OPh54iiVnTRfiX4dt/GPgweLPCtzJF4m8E3vi6w0bxppHh/XpX0uP6EoAK8j/a\ -A/wCSD/Gz/skfxI/9Q3Wq9crhvih4Yv8Axr8NPiJ4N0qazt9U8W+BfFvhjTZ9QkmisIL/AF7QNQ0qzm\ -vpba3lkjs1uLuNpWjilcIrFY3YBT52cUqlfKc0oUYOpVrYavCMVvKUqUlFLzbaSPtPDfMMFlPiJwFmu\ -ZYiODy7LM6yvEV6s9IUqNHHUKlWpJq75YQjKUrJ6Jnc1Vt7OG2mvpo3umfUbpLy4W4vr27hjmSys9PV\ -LG3urh49LtfIsYGMFssMDTvNctGbm4uJZfOfh38SofF8MWj+I7Kz8F/Eu2s7u+1/4bXOoX9xrGk2lrf\ -rYPqWnzazoOlyeKvDi3E1vbtremWtxoU18J7bT9Tv0hFxJ6hXRg8Zhsfh6eKwlVVqNRJp2cWnZNxnCS\ -U6c43tOnOMZwleM4xkmjx+I+G874SzfF5FxDl8suzLByalFyhUp1IqTjGthsRRlUw+LwtXlc8Pi8LVr\ -YXE0nGth61WlKM34zZ+B/EnhmF7v4ZapdeHbK3ur6Jfhh45mGveCLi0sL24t7ceFtQ0/ULnUPhna3dj\ -p+lQ6XFZXF5oOiaZcEjwSdRaWGP5T+KnxP8AEmrePP2R/Hum2vifwn/wn8nxG0rwVcfDfxhf2nxDXwp\ -8X/CXgrwto2pjVbL4QeI7rwp4yax8YzC6s9B0LxLqNsYmXw7qEuqvZXlt+iVfl74wu9RsvCX7DE2j3v\ -h/T9Wf4B+O7TS5/FmqeFtH8LSajqHwM8KWFlZeJbvxz458O6JN4fubm5itry11i/uNKvra7kstQ0LxR\ -aXE3hrVvIWEp4bM8PgMPKVLL8XhsVKdBO9K9OeGpxVOLu6MeWvO8KLpwb5Xy3Tv9++IMbnXBOb8V5tS\ -o4/i3h7OsjoYXNJ07Y7kxWHzrFVZYupTcIZjW9rleG5cRmVPF4iMHUpqryOCh9Df8E/dM8JaV4G/4K9\ -ReBJEbwfff8E7/izr/h6GOy0zTE07TvE/w51rxJFoo0zTPiV4wGmfYDqrWX2a78R6nqtubDydZe31dL\ -20t/7dK/ji/ZR8TeJL/wAL/wDBXbwh4j8AaV4An8FfsCfHi0htf+EW1/RPFus2U3w+u9L8O6z4ivPGv\ -hrR9Xt9KfwH4e8GLo2hW2ieFfCmiWEYbwx4I8Kx6lqFpP8A2O1WBp06Wd5tSpQVKlSw2BjGMUoxjGLx\ -aUYpWSSSSSSslojxc3xeKx/hzkGOx2JqY3G43ifiirWrVZyqVatWplfCE6lWrUm5TqVKk5Oc5zblKTc\ -pNttnwB/wTT/5N1+I3/Z//wDwVi/9em/tkV9/18Af8E0/+TdfiN/2f/8A8FYv/Xpv7ZFff9e8fnwV8A\ -ftkf8AJxX/AASd/wCz/wD4j/8ArrL/AIKWV9/18Aftkf8AJxX/AASd/wCz/wD4j/8ArrL/AIKWUAff9\ -FFFABRRRQAUUUUAFfkD8Kv2o/gT+zh+0V/wU5svix45/s7xb4+/b/8ACn/CtPhT4P8ADPjH4r/Hb4s/\ -8Ir/AMEsv+CXkvjL/hTv7P8A8JvD2t+Nvi9/YOma7pupeIf+EZ0DVf7A0eSXW9Z+w6RbXN7F+v1fAHj\ -D9jrWPhp8dvjF+2H+xhefD/wN+0b+0L/wr0/tReGfjFb+O/Fnws/ao0f4K+DrXwn8I9AutZ0vxOdQ/Z\ -k+IGkeH9OudB0fxp4Y0zXtC0/TviD4h1Txb8KviZrMPhqTQQA/4Vp+1P8AtUf8nEal/wAMr/s/33+n2\ -v7PnwC+LHxF0r9qfxX5P/Ez8H3nxq/bE+DvjLw5/wAKX8j+1bf/AISP4e/Cn+1tniP4dWf2f4/eNPh/\ -rPiHwfrP1/8AC34T/Cz4HeBNC+FvwU+Gnw/+D/wy8L/2n/wjPw6+Fvg3w58P/Anh3+29Y1DxFrP9heE\ -fCem2mn6R9r8Qavqt9dfZ7eP7ReancXUu+eaR28A+Fv7XOj6z470L4EftB+EP+GW/2mvEf9px+BvhJ4\ -98e+BNf0f9oS18LaPqGpeNvG/7I3j3Q9XX/he/w/03+wPEN1eWd1pXhn4j+HdCj0fxB8Q/hv4EsvFHh\ -tdU+v6ACiiigD4W/bA/4Jwfslftu/Ytf+Mfw5/sv4xeHNJttL+H37Sfwv1Gb4cftFfDldI/4Sa98KQ6\ -B8UfD6Lc+IPCekeKfFmqa9a+EPEseveBbvXY7fUdZ8L6pJAi1+E3x3/Z5/a4/YhuJNV+L2j+E/jj+z5\ -cfaDbfHv4Qx+PtIPgW/OqJf3Nl8Vvhr41sddj/Zs+CujeDNYZ38efEL4u+KfDNjo/wO8W+L/iL8VfDm\ -seJ/BvgS4/rCooA/kU8AfEXwJ8VfC2l+Nvhv4u0Dxt4U1m0sr3Ttd8OalbanYzQajp1lq1osj27k2ty\ -2m6jYzGCYRzIl3GZI1LAVv6Lf3GpaZbXV5afYb799bajZqup/Z7bU7G4lsdSisLjV9JsZ9S0sX1tcfZ\ -L02kEd9beVeQJ5E8ZP6sftTf8Eh/g78XPFPiP4w/s1a54e/Y8/aA8V3er654z8V+CPhL4X1v4ZfF/wA\ -ba3qPiG/k+Inx2+HnhnUfCuveN/G1rqHjXxbrButF8beFo/F3iGDwzcfFm3+Jfh7wb4d8L2f4O/F3w1\ -8XP2W9R8JfDL9ufwj4A+A7HxT8L7TRfiZ8MPEnjbVP2UPGttoHibRdc+E/hT4XfEn4neFPC2i6V8Qb/\ -wAaX6aTN4MtLe++I8ul/B3xl4i1LwhpHw107w18QLkA9x8a+BvC3xD0Obw54u0w6npU5kbbDf6lpF9b\ -tPZ3em3bWOsaLeW95ppuNJ1DUrK5NvPF9psNVu7G48y0u7iGX51+Glz8QvCvwX+E1xcWV78S/CE/gz4\ -V6go8Pibw1478Fada2fhzWtTu9UXQr1f+FkeHrXTU1JYNP0nToNXuotIsNDudO8StrGpapafUena5om\ -r+X/ZOsaXqnnaXpeuRf2dqFpe+bomufa/7F1iP7NM2/S7z+z7/AOy3AzDcfYpvKd/LfbwXwP8A+SK/C\ -D/sl3w//wDUT0muDEZfTq1HiaNSWDxlkva03bmtsqsH+7rxSvGKqxk6alJ0ZU5vnX1mT8XY3L8FHJcy\ -wtHiLhtylJ4HGR51Rc3epUy/FK2LyutUnGnUrVMBWoRxc6FCnmFPG4Wm8NLa8J+PvDfje71aPwzrnh/\ -V7fR7bS11K2s9Wc+KtC1i9l1RbzRfGPhC5sYrrwdfQpZW6iC+Md99pF7a3NlZyWJM/wCe3in+yY9F/w\ -CCe2oa3eX2nafoPwxuvFTajpup6zo15p954R+G3w88T6ZfpqmgXVpdWUcOp6TZyyuur+GovKicXPjDw\ -bbGbxVo/wBgan4QXxL8bPGV3a+JfFvhLWdL+FvwoXTda8K6yLZoVvPFvxqW7XUPDurW17oniYNbRSRw\ -jV9K1D7F9rluNP8Asl4y3K9j+x18Krfw/wDt3f8ABNj4d+Ob3SfiVaeEx8dG0o6t4T0q00awuPhr8A7\ -e68B6hpmh3Ut61vq2na34T0PWoby4vLu6g16J9QsJrGGLT7LT/NcM3eZ4adTDQk6GFxcFiINKg6lWeF\ -lSU6Uqnt4NujPmjD2sFHlarOUnGH2Uq/h/HgPO8Nl2fV8LPNM7yHEyynE0qtTM6eGwWGz2jjZ0MbQwk\ -cqxVOmsxw3satepluJq1XXi8uhSowrYj0n9hj/gnX+0D4j0P44j4deLtO+HHwk/aB+Bc3wE8X/EHxl4\ -I0pI77wzqXgHxL4Cm1LwJ4K8M+F7TS/j5peraFLoPimHxN4V8Y6V4aiv/F2gahp3xN+Mn9meONJ1n+r\ -6iiu7AZc8LWxWMr4iWLx2O9mqk3eEFGlzezhSpc0o04R55veVSTk3UqTtBR+O4g4np5rluUcPZXlcMm\ -4ayGri6+Got06+LqYnHLCwxWKx+PVChPF4irSwWCoKMKWHwdClhaf1bB0alXFVMR8Af8E0/wDk3X4jf\ -9n/AP8AwVi/9em/tkV9/wBfAH/BNP8A5N1+I3/Z/wD/AMFYv/Xpv7ZFff8AXpnyQV8Aftkf8nFf8Enf\ -+z//AIj/APrrL/gpZX3/AF8Aftkf8nFf8Enf+z//AIj/APrrL/gpZQB9/wBFFFABRRRQAUUUUAFFFFA\ -Hn/xS+E/ws+OPgTXfhb8a/hp8P/jB8MvFH9mf8JN8Ovil4N8OfEDwJ4i/sTWNP8RaN/bvhHxZpt3p+r\ -/ZPEGkaVfWv2i3k+z3mmW91FsnhjdfkD/hWn7U/wCyv/ybvqX/AA1R+z/Y/wCn3X7Pnx9+LHxF1X9qf\ -wp53/Ez8YXnwV/bE+MXjLxH/wALo8/+yrj/AIRz4e/Fb+yd/iP4i3n2j4/eC/h/o3h7wfo33/RQB4B8\ -C/2l/hZ8fv8AhKdC8Lat/wAI/wDFr4Zf2JZ/HT9nvxhf+HLL47fs+eI/EH9rrpHhz4xeBNE17UP+Ef8\ -A7Q/4R/W7jw9rdndah4V8aaPZReKfAuv+J/CWoaXr197/AF4B8dP2aPhZ8fv+EW13xTpP/CP/ABa+GX\ -9t3nwL/aE8H2Hhyy+O37PniPxB/ZDav4j+DvjvW9B1D/hH/wC0P+Ef0S38Q6JeWuoeFfGmj2Uvhbx1o\ -HifwlqGqaDffP8A/wALL/an/ZX/AOTiNN/4ao/Z/sf9Atf2g/gF8J/iLqv7U/hTzv8AiWeD7P41fsd/\ -B3wb4j/4XR5/9lW//CR/EL4U/wBk7/EfxFs/s/wB8F/D/RvEPjDRgD7/AKK8/wDhb8WPhZ8cfAmhfFL\ -4KfEv4f8Axg+GXij+0/8AhGfiL8LfGXhz4geBPEX9iaxqHh3Wf7C8XeE9Su9P1f7J4g0jVbG6+z3En2\ -e80y4tZdk8MiL6BQAVz/izwn4V8e+FfE3gXx14Z8P+NPBPjTw/rPhPxj4O8WaNp3iPwr4s8K+I9OudH\ -8Q+GfE3h7WLaa017w/f6ReXlre2V1DLbXVtdSQTxvE7KegooA/n1/aF/wCCPni74Xatf/E7/gnz8QrX\ -wN4Js7rUNc8R/sM6p8L/AIZal8ONa0u71r+1dV0j9mrxTa694Hufhv40iTxF8QdQ0fSfGviTVfDWo3N\ -j4L+G2n+JfhD8MPD2myeH/wAw/B/xh8H+BvGOlfsv/FHw9q37Ofx58KeFdEWH4EfFGy8V+HNabw/Zya\ -V4ShuPh94l8daBptv8afCdn4ve+8LJ4q8MTa34W1/XfBusP4R8Q+KdCgtPEGof2jV4V+0R+zX8F/2q/\ -h1c/Cz45+ErvxT4Snu5r+1k0Pxf43+HHjHQL690LW/CWr3vg/4lfDLxJo3iTwRd6l4H8U+MPDmrSaPq\ -1i+r+GPG+veGdTa70HXNW068AP5YfDt9Zaj8ZPiHcafeWt9BH8OPhdYyTWdxDcwpe6X45+PGm6lZvJA\ -7Kt1b6jaXVvPGTvhntpIpAsiMo9n/AGdv+Um/7AP/AHdV/wCs/a3XWfGz/gmx+1d+yPret/ED4O+MtX\ -/bM+B+sGCC/wDCWo/B/wCG3hH9ob4J6Np12uv6jrOqXvwLstCsviz8FtPi8Q/Fi/sfDnwz+Fl9400KL\ -QvCPgDwD8LPGcniHVvEnhz52/Ya+OXw4+Nv/BSn9iWXwNq90dc8CeIP2sfBnxL8C+ItJ1Lwt8RPhX49\ -sP2edYbXPh98TPA+vW0Go+DPG2m3huLPUdPvII5bW+067s5P39rOiAH9hNFFFAHwB/wTT/5N1+I3/Z/\ -/APwVi/8AXpv7ZFff9fAH/BNP/k3X4jf9n/8A/BWL/wBem/tkV9/0AFfAH7ZH/JxX/BJ3/s//AOI//r\ -rL/gpZX3/XwB+2R/ycV/wSd/7P/wDiP/66y/4KWUAff9FFFABRRRQAUUUUAFFFFABRRRQAUUUUAfIHx\ -S/ZG0fWfHeu/Hf9nzxf/wAMt/tNeI/7Mk8c/FvwF4C8Ca/o/wC0Ja+FtH0/TfBPgj9rnwFrmkL/AML3\ -+H+m/wBgeHrWzvLXVfDPxH8O6FHrHh/4efEjwJZeKPEjap5//wANrf8ADP8A/wAUt+31oH/DP/8AYv8\ -AxLf+Guv7K/s/9hP4ofZPl/4TL/haf/CV63/wx/8Abf7Q8G2f/CM/Gq+8L+b4x8a/8IL8OPFnxg/sz/\ -hKtT+/6KACivgD/hk34p/s+/8AEz/YY+L3/CHeErD9/wD8MdfH248R/Er9li8sbX/SP+EV+Cvif7XN4\ -2/Yu8zTNF8I+FvDlt4WvvEvwa+HPhy1vLjRP2etZ1efzj6B8Lf21vhZ458d6F8FviNoHxA/Zd/aN8S/\ -2n/wjP7PH7SuleHPBnjvx7/Y2j6h4r1n/hSPjTwn4r17wF+09/ZfgW0sdc8S/wDCrPGXjb/hCrPxBYW\ -njf8A4RvWZZNKhAPr+iiigAr5g+Nf7K3hX4ueKtP+KPhr4i/GD9nr47aP4ftfCel/HP4B+LtO0DxVc+\ -FbLUdVvrHwz8Qvh9468O+Ivh78fPD9hH4p8fp4fsviP4L8YW3g65+JniLW/BUfhzxLqk2tD6fooA+AP\ -+Gsvin+z7/xLP25/hD/AMId4SsP3H/DYvwCt/EfxK/ZYvLG1/0f/hKvjV4Y+yTeNv2LvM0zRfF3inxH\ -c+KbHxL8Gvhz4ctbO31v9oXWdXn8k/f9FfAH/DFP/DP/APxVP7Auv/8ADP8A/Yv/ABMv+GRf7V/s/wD\ -YT+KH2T5v+EN/4VZ/wimt/wDDH/23+0PGV5/wk3wVsfC/m+MfGv8AwnXxH8J/GD+zP+EV1MAP+Caf/J\ -uvxG/7P/8A+CsX/r039sivv+vxh/4JT/tQeFYvAPiH9nr43p4f+B/7SPir9t//AIKk6r4L+HmseNNO1\ -Twr8eJ4f+Chf7YHjP4nXX7J/jjVbHR7v48+H/B+r2ni/TPEVvJoHh7xlodt4YtPEvibwV4e8L+LPBWr\ -+Iv2eoAK+AP2yP8Ak4r/AIJO/wDZ/wD8R/8A11l/wUsr7/r4A/bI/wCTiv8Agk7/ANn/APxH/wDXWX/\ -BSygD7/ooooAKKKKACiiigAooooAKKKKACiiigAooooAK8/8Ail8LfAnxo8Ca78NviToX/CQeEvEH9m\ -T3NtBqeseH9Y0rWPD+saf4m8J+LvCPizwzqFnq/gT4gaF4t0fQ9b8OeI9EvtP13w5rvh/Ttc0PUdP1f\ -T7K9g9AooA+AP7C/ax/ZO/0f4eaf8QP29vgKf3kHgbxl8UvhtoX7ZPwdtbX/iR+HfBHwn8bfEXTPDPh\ -j9qr4frZT+GXubz4teP/AA38R9Hg8KeJvEOs/Ej4ya74l0jw3oP0/wDBT47/AAz/AGg/CuoeLfhlqni\ -Ce20PxBdeE/FXhrxz4A+IXwh+JngPxVa6dpWujwz8SfhB8XfC2heK/hp4guPC3iHwvrljZa/ounXOo+\ -HvGOieIbCO50TWtKv7z2CvmD41/sh/Br42eKtP+Kd1ZeIPhh+0H4e8P2vhjwd+058FNen+Gnx98NeH9\ -J1HVfEXh7wfqHjbR4jF8VPg/ZeNtWbxBL8NfHdl4r+F+ua1p9pd+KPBWurAsVAH0/RXwB/wu39o79mH\ -/iQftH/Cj4gftDfB/Rf+JfoX7W/7OHhW6+LHxTu9Htv3Wman+05+xx8LfA1p4n0j4gXd7q/hXQ1vvgj\ -oXxI0LXtR0/xB451vwt8D/B4t/D+l/b/hPxZ4V8e+FfDPjrwL4m8P+NPBPjTw/o3izwd4x8J6zp3iPw\ -r4s8K+I9OttY8PeJvDPiHR7ma017w/f6ReWd1ZXtrNLbXVtdRzwSPE6sQDoKKKKAPzA/Yl+E/ws+OP7\ -HXxj+Fvxr+Gnw/+MHwy8Uft/wD/AAVP/wCEm+HXxS8G+HPiB4E8Rf2J/wAFZv2uPEWjf274R8Wabd6f\ -q/2TxBpGlX1r9ot5Ps95plvdRbJ4Y3X0D/hWn7U/7K//ACbvqX/DVH7P9j/p91+z58ffix8RdV/an8K\ -ed/xM/GF58Ff2xPjF4y8R/wDC6PP/ALKuP+Ec+HvxW/snf4j+It59o+P3gv4f6N4e8H6Mf8E0/wDk3X\ -4jf9n/AP8AwVi/9em/tkV9/wBAHgHwL/aX+Fnx+/4SnQvC2rf8I/8AFr4Zf2JZ/HT9nvxhf+HLL47fs\ -+eI/EH9rrpHhz4xeBNE17UP+Ef/ALQ/4R/W7jw9rdndah4V8aaPZReKfAuv+J/CWoaXr198/wD7ZH/J\ -xX/BJ3/s/wD+I/8A66y/4KWV9AfHT9lz4E/tH/8ACLXvxY8Df2j4t8A/23/wrT4reD/E3jH4UfHb4Tf\ -8JV/ZEXjL/hTv7QHwn8Q6J42+EP8Ab2maHpum+If+EZ1/Sv7f0dJdE1n7dpFzc2Uv5ganeftT+L/29v\ -2Mf2etb8R/D/8Aai8Gfsg/tAeNvj38W/2jfCngr4i/C7x38LfDms/sH/tTfA7wF8Lf2h9N03wBffCLx\ -Z+0BezftFfB7xJrUnhPx34J8ValZ/GTSte0b9m7wv8ADmJvFgAP2+ooooAKKKKACiiigAooooAKKKKA\ -CiiigAooooAKKKKACiiigAr4g8WfsY6d4S8VeJvi/wDsa+JfD/7Kfxx8X+INZ8T+OBD4S8VeNv2YPjL\ -4g8Z6jc3/AMQ/GHx+/ZL8JfFTwZonj/4watc3FhfyfErSdS8MfFCTUPBPh6w1Xxrq/ge21rwR4g+36K\ -APiDwn+2FqPg/xV4Z+GH7anw38P/sk/ETxz4g0bwZ8LPF83xj8K/EX9l/9oH4heJNRtrfRfhX8Afjfq\ -2leFdb1b4wG21nw9FH4Q8b+BPAHibxHqEXiE/DnSvHnh3wj4g8TWf2/XP8Aizwn4V8e+FfE3gXx14Z8\ -P+NPBPjTw/rPhPxj4O8WaNp3iPwr4s8K+I9OudH8Q+GfE3h7WLaa017w/f6ReXlre2V1DLbXVtdSQTx\ -vE7KfiD/hm/42fsyf6R+wjrHw/v8A4ZP++1P9jj9o/wAb/F2D4WaddRf8SfQrT9mP466fJ4v1D9iz4f\ -6Z4fu7NG8Bad4A8c/Dgad8M/D/AIe8A+D/AIVT6j4p8VauAH/BNP8A5N1+I3/Z/wD/AMFYv/Xpv7ZFf\ -QHx0/aX+FnwB/4RbQvFOrf8JB8Wvib/AG3Z/Av9nvwff+HL347ftB+I/D/9kLq/hz4O+BNb17T/APhI\ -P7P/AOEg0S48Q63eXWn+FfBej3svinx1r/hjwlp+qa9Y/nB+yJ4G/wCCit18KfFnwuPw28P/ALB/hbx\ -B+0/+278XNd+JXxY1z4X/AB//AGlZ/Cv7S37aHx9/aC0DRPg98I/hB428Q/DfwJ4gg+F3xv8ACr2Xj3\ -xf408a22i+N/h/rOiar8DPGHhSfTfE2o/o/wDAv9lz4E/s4f8ACU3vwn8Df2d4t8ff2J/wsv4reMPE3\ -jH4r/Hb4s/8Ir/a8Xg3/hcX7QHxY8Q6342+L39g6Zrmpab4e/4SbX9V/sDR3i0TRvsOkW1tZRAHz/8A\ -8K0/an/ao/5OI1L/AIZX/Z/vv9Ptf2fPgF8WPiLpX7U/ivyf+Jn4PvPjV+2J8HfGXhz/AIUv5H9q2/8\ -Awkfw9+FP9rbPEfw6s/s/x+8afD/WfEPg/Wfr/wCFvwn+FnwO8CaF8Lfgp8NPh/8AB/4ZeF/7T/4Rn4\ -dfC3wb4c+H/gTw7/besah4i1n+wvCPhPTbTT9I+1+INX1W+uvs9vH9ovNTuLqXfPNI7egUUAFFFFABR\ -RRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAf/2Q==\ -' +Pk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigAooooAKKKKACiiigAooooAKKKKACiii\ +gAooooAKKKKACivym/4KrfFX4g2ng79nr9k/wCCPj7xR8Nfjb+2n8fPB3wu0Tx14F1jUNC8bfD/AOF/\ +hjUdP8X/ABk+Ivh3VNJu4Lm1m03w9babbTmGRHa28RTBXU81xH7BP7Y/jiH/AIJ3/GjxJ8ZX1H4h/tC\ +fsAW3x8+F3xx07XfEV5F4g8beK/2dtL1zWtKutW8Tapa312brWfC1ho0NxrFzBeyz6jDf3TrcypJGQD\ +9kKK/Db4E/8FkvFvxP8dfsjWPxH/Yi+InwV+D37Z1wfDXwh+M+qfFLwp4stNS+IFtYR/b9GHgvTPD9t\ +fW/hVtfkFrp+r38mnz6laSJqcGkrb+ckGhpP/BYzWfFf7RPjT4V/D/9jX4kfEX4WfDn49ar+z943+I/\ +gj4k+C/E3xd0TxDoOstoOueMP+GTdEsbnxjdfDi1vI7ieTWFAt1sraR32XsclggB+3NFflj4o/4Kd6H\ +8OfEP/BRbwr8UfhX/AMIXrv7BngzQPiLotr/wny6lH8e/BfjXw7e6t4G1PRJ5fBlqPB93e62fDmkXMO\ +NXjsb7xPDGbi4aKRK8G+K3/BYbx18P9X+Bfw78P/saXfjH44fFT9mjwn+0/wCLfhnqn7Rvw9+GVv4J8\ +J+MZ7uLT/CHhLxF8QvDdlN8YPiPCtlcC40bSdLhvGlBgs4rt4ro24B+49FeY/Bf4lP8YvhT4D+J8vgb\ +x78M7jxr4csdbu/h/wDFDw1qPg/x/wCD76dWS+8P+KPD2qwRzWOo215FPHu2+VcRqlzbtJbzRSMUAen\ +UUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQB+P37R/wDwTB0/9tr9uF/i7+15YeDPiD\ ++yf4A+BNv8Pfgv8JdE8e/FHw34xX4k6r4j0/xD4q8f+MW8KQaMmmxGE6lp8MNlrl6t3BYabNcwQyQtG\ +PLfBP8AwSc8Ufs5eOf24vB37KN18N/BP7Jf7XP7ImufDHSvhl4o8d/FHV/Evgb9oP8A4RLxF4S8P+Jv\ +tWvaFrsl38P5rbxJrc2oXD6xPqMcuusltpz21hawSfP/AO17/wAFSv2QLX9rP9lu8+A/7b3j74mzeLP\ +ip8I7LxVdfs0eN/Hn7Sv7Pug+ANJ13xO/iD4X6R8FP2S/C3iif4x/GD4hXEbaDm+0/WpfDszaRcx6h4\ +emudNttW+Y/AX/AAUJ/aLt/wDhpnxBr/hH9tzUtIt/gd+0De/H7xHq3xV+Ffwj0H4GfEHWvj/e2/wA8\ +Z6T4d+L3jfU/Fn7J3hfSfhbc3nhzWtEtPhZL8Srlre18Q+FfhZ46nhg1G5AP1IT/gnH8bl+F/8AwSS8\ +E/8ACUfCr+1f2CviB4L8V/GC4Gt+Lf7P8Saf4d0W006/h+G0v/CDeZrF69xA7RLqkWjoykF5EbKj5k/\ +ae/4JAftY/tG/GfxJqWr/ABI/Y+PhHXfi5YfEHQ/2o7f4Par8Of26Ph94bsNZsNT03wfpmq/CHSNG8N\ +eNrrT7KyWzt9X1tpdTnAFw1xat5MNv86eD/jx+1T8S/wBl7wP4r8R/tK/AD4E/s/8Aiv8AaF8R/EHw9\ +41vf2/P2rf2kvih4Ehg+BOr6roP7Evxo+IvwJ8M+Db2yefX7iLxLBqOtfGnSNdlm1nSdB/4R6W8ht9C\ +uOh/a78T/t9eAP2V/wDgmF8Tde/ay+OOj+Mv2uf2pf2S/gj8TP2WfD8+k/s9/Cjw14U8a/Cz4geNLbw\ +RY/GVfCni79ojwp4rln+G/hKz8U+Jtb+L3irU9TvtY8Sao2iWUN/Y+GdGAL3/AAUU+GPgf9tr/gqt8D\ +P2evgdr3izU/EknhfTPhb/AMFENGtvBvirR/Cum/AX4dePvAH7QnhK38SeKNS0SCw1e/1Ke3lhsrizk\ +uYjeLo1k1yC5tq/Q3/gox+wZ+0h+1F420TWfhfN+xl8SfhyngObwbL8JP2v/hBc3sfw51ma8aS4+IHw\ +j+Lfwo8PxeL9M1Oex+yxvpVzqi6Uktj5/lzebHHZ/nR4Y/aG+OvxH/4J5/8ABSXxr4F+P/xU/Z9+IHw\ +I+Mfirw94q+AOu/FzxZ+0Z8aP2cJvhZap8NfF/wAM9H/ao8X+LbjUtYsdZ+K/g/xbdHX9Nn1Kztf7E1\ +XR/D97HKk2oQ/vF+198TfhFpXws8e+HfF3x1vPhhfeGZfh1qfil/BXxO1j4b6/oVv4t8S3Fr8P7L4of\ +EHwJ4b1nXvgR8IvE/iHQL7SdS8YR2unmx0+DUp7TVbaS1ldQDQ/YT/Zu179kP8AZN+DH7Onif4gXfxQ\ +134ZeH9R03UfGV0l1FFeTat4j1rxGNK0mG+uJZofDumRazHpmmJK+5dP0e2Xy4QBDGVzP/BOPxp41+I\ +H7FnwM8T/ABE8QeJvFvjG40bxLpmseKvFYlm1HxL/AMI7458UeHtP12w1i5kafxd4WutL0uyl0XX7rZ\ +eeIdHksdcvIobnUJYkKAPtyiiigAooooAKKKKACiivH/jX+0L8Av2a/Cun+Ov2jPjj8H/gD4J1bxBa+\ +E9L8Y/Gv4l+C/hX4V1LxVfadqusWPhnT/EPjrWrC0vPEE2kaFrl1FZRzNcyW2jXc6RmK3mZAD2CivgD\ +/h6B+xZq/wDpPwt+IvxA/ab8Pp+4vPHv7FP7Nv7Tv7dHws0jWF/eXHhHX/i3+x18HPHPhjw78QLeyl0\ ++9uvDl9q1vrtpp2v6Vqd1p0On6vpdzdn/AA0x+2n42/4lXwt/4Jr/ABA+H/iC3/4mF5rP7a37Tn7MXw\ +f+Flzo8X+jXGmaB4m/Y68b/tE+J774gPe3eny2tjfeCtL0KXTrLVbi68U2WoWul6TrYB9/0V8Af8IZ/\ +wAFNfiJ/pfiL47/ALIH7Mnh/wAR/wDEv134d/Cf4DfE/wDaY+Kfw70dv+JTqep/DT9rD4pfF/wN4Y8R\ +fEC4sop9Y0a+8R/s8XGheHdR1S20rV/C3jvT9IuLzxEf8MC/8Jb/AMl9/bU/b/8A2gP7P/5FP/jI7/h\ +j/wD4RL7X/wAh3/lGj4N+B3/CxPt/2bRv+R1/4Sj+yP7F/wCKc/sT+09e/tcA+3/Fnizwr4C8K+JvHX\ +jrxN4f8F+CfBfh/WfFnjHxj4s1nTvDnhXwn4V8Oadc6x4h8TeJvEOsXMNpoPh+w0izvLq9vbqaK2tba\ +1knnkSJGYfEH/D0f9hPWP8Akk/xz/4ao+zf8h//AIYY+GXxi/b7/wCEE87/AJBX/C0f+GKfh949/wCF\ +T/2p5Wpf2J/wk39k/wBu/wDCPav/AGN9u/sbVfsfQeE/+CaH/BPTwX4q8M/EPR/2J/2YLz4reE/EGje\ +M9L+Nviz4K+AfHvx9uviFoWo22uWPxU8TfHvx1oeo+MvGnxgfxJaxave+L9Z1y/8AE2o600mtahqt1q\ +s014/2/QB8Af8ADWn7THjv/Qfgj/wTn/aA/wCJ7/pngD4pftR/Ev8AZ7/Zs+BOseHP+QnZeI/HOn+HP\ +iV49+Nvwn/tTw1E7aZomrfAv/hKrPWNU0/RvGWgeDv+J3faEf2b/wAFTfHf/E3/AOEy/YA/ZX+zf8S3\ +/hXv/CtP2iv2+/7Y8n/Sv+Ey/wCFxf8AC2P2a/8AhGvtH2z7D/wjP/CC6t9j/wCEe/tT/hLL7+2f7H0\ +L7/ooA+AP+GHviL4g/wCJR8WP+Cjf7f8A8W/h/d/8h/4e/wDCSfssfs7/APCQfZ/9K0r/AIvF+xT+yh\ +8L/ib4P+ya1Dpt9/xTPjrQ/wC0P7N/svWf7T8P32q6PqB/w6x/4J96v/pPxS/Ze+H/AO034gT9xZ+Pf\ +21p/E/7dHxT0jR1/eW/hHQPi3+2Lr/jnxP4d+H9vey6he2vhyx1a30K01HX9V1O106HUNX1S5u/v+ig\ +AooooAK+AP2mP+K2/bT/AOCa/wALdK/0fxB8P/iB+07+2trN5qH7rR7n4WfB/wDZi8b/ALHXibQNMuL\ +bzZ5viBP8Tf8Agol8FL6xtZbeHTpdC8L+Kbq41W11Cy0nS9b+/wCvgD4jf8pTf2N/+zAP+Cln/rRX/B\ +J2gA+N3/GIHxT8W/tmaZ/pHwS+KP8AwprwT+2L4Pj/AOJTY+AP7F8Rv8PfDH7c+l3Vv5GkWv8AwjXhL\ +xjoWnfHHV/FLw/8Wa+C3hrxPb+KdItvgtD4O+IH3/RXwB+zx/xiN478LfsLaz/oPwFsvh/4U0r9gbxv\ +rv8Ao91qfhzwfo/jSPxV+xTqGsQ+dB4p+IHww+GXgPwzrPhbVdWn07xV46+HGt3TSaf4w134RfFb4ka\ +yAff9FFFABRRRQB4B8dP2sf2WP2X/APhFv+Gl/wBpb9n/APZ3/wCE4/tv/hCv+F6fGT4dfCT/AITD/h\ +Gf7I/4ST/hFv8AhP8AxHp//CQf2f8A8JBoP277J532T+27Pz/L+0w7/n//AIeNfCLxT/oPwF+EH7X/A\ +O034g1P9/4Di+E/7Jvxs8L/AAs+K2jr/preLvhp+15+0J4V8DfAzxF8P7jwvFd61o3iN/ihb6F4r06K\ +2XwfqPiDUNX0Kw1X4A/Z3/4sb+0d+2V/wVQuf3Pwf/bT/a/+IP7OH7X9hrH73R/2S/hZ/wAE1Lr4w/s\ +R/Bb9pyPxjYbZ7/4f6j8Tfgd4svfiQt7on9neFtC/ad0TxNqfiDwx4P8Agn458TePf3+oA+AP+Gh/27\ +PHf/JJ/wDgnV/wrn+yv+Q//wANz/tc/B34L/2x9u/5BX/Crv8AhinRP2lP+El+z/Y9S/tv/hJv+EL+x\ +/btI/sb/hI/tWq/2Ef8Kq/4KOfEL9x4/wD2vf2f/gR4S8R/8TLVtB/Zc/ZX1TX/AI7fDPzP+JtYeDfA\ +37S/7S/xm8V+CfH32HU47PStT8Ta3+z1Yf8ACTaPHqFzpvhPwJq+pWE/h77/AKKAPgD/AId8eHPFX/E\ +w+On7WP7f/wAd/FsP+h6d4u/4bD+Kf7Jv9neHI/39p4c/4V1/wTovfgt4J1rydTuNXuv7b1Twtf8Aiq\ +5/tj7Dfa/daRpuh6dpXsHwU/Yi/Yv/AGa/FWoeOv2c/wBkT9mD4A+NtW8P3XhPVPGPwU+AXwp+FfirU\ +vCt9qOlaxfeGdQ8Q+BfCdhd3nh+bV9C0O6lspJmtpLnRrSd4zLbwsn0/RQAUUUUAFFFFABRRXn/AMUv\ +ix8LPgd4E134pfGv4l/D/wCD/wAMvC/9mf8ACTfEX4peMvDnw/8AAnh3+29Y0/w7o39u+LvFmpWmn6R\ +9r8QavpVja/aLiP7Reanb2sW+eaNGAPQKK+AP+Ho/7Cesf8kn+Of/AA1R9m/5D/8Awwx8MvjF+33/AM\ +IJ53/IK/4Wj/wxT8PvHv8Awqf+1PK1L+xP+Em/sn+3f+Ee1f8Asb7d/Y2q/Yz/AIa0/aY8d/6D8Ef+C\ +c/7QH/E9/0zwB8Uv2o/iX+z3+zZ8CdY8Of8hOy8R+OdP8OfErx78bfhP/anhqJ20zRNW+Bf/CVWesap\ +p+jeMtA8Hf8AE7vtCAPv+ivgD+zf+Cpvjv8A4m//AAmX7AH7K/2b/iW/8K9/4Vp+0V+33/bHk/6V/wA\ +Jl/wuL/hbH7Nf/CNfaPtn2H/hGf8AhBdW+x/8I9/an/CWX39s/wBj6Ef8MI+I/FX/ABL/AI6ft7/t/w\ +Dx38JQ/wCmad4R/wCFs/Cz9k3+zvEcf7i08R/8LF/4J0fA/wCC3jbWvJ0y41e1/sTVPFN/4Vuf7Y+3X\ +2gXWr6boeo6UAff9fAH/D07/gn3q/8Ao3wt/ah+H/7TfiBP3954C/Ypg8T/ALdHxT0jR1/d3Hi7X/hJ\ ++x1oHjnxP4d+H9vey6fZXXiO+0m30K01HX9K0y61GHUNX0u2uz/h1j/wT71f/Sfil+y98P8A9pvxAn7\ +iz8e/trT+J/26PinpGjr+8t/COgfFv9sXX/HPifw78P7e9l1C9tfDljq1voVpqOv6rqdrp0Ooavqlzd\ +/f9AHwB/w2j8XfG3zfAX/gnv8Atf8AxA8P69/xL/Afxb+LMHwT/ZP+FlzrEv8AxLW1P4l+Av2hPi7pH\ +xz+F3w/03xQt3b6zfP8ENU12XTtIudc8H+FvGen3WhNrfxB4Ttv+CknxW/4KSfH28vNZ/Yg/Zl8bfCr\ +9iD9kS28PeHta8M/Hn/gon4VsPCvxt+PP7bsvjHWfhp4xl8Wfsz3fwW8QeJtX+AngWDxxpkGheILbxP\ +bfBj4e3V1qwl8N2dnafu9XwB+zx/xXf7dn/BRX4s/8gr/AIVz/wAMjfsMf2B/x/f2x/wpf4O63+2t/w\ +ALR/tX9z/Z/wDaX/Dyj/hGf7E+zT/Y/wDhS/8AbP8Aa91/wkf9laEAH/DJf7THjv8A0743f8FGP2gP+\ +J7/AKH4/wDhb+y58NP2e/2bPgTrHhz/AJBl74c8Dah4j+Gvj342/Cf+1PDUSLqet6T8dP8AhKrPWNU1\ +DWfBuv8Ag7/iSWOhfMHxe/Y9+CHwD/a0/wCCVvjrwYvxg8VeNr39t/4o+E7Txj8fP2mP2lf2p/FXhbw\ +rqn/BMP8A4KL6x4i8M/D3xD+058W/F938M/D+tav4d8JXXiCy8PTaZbeIrnwL4dn1yPUJfD2iNYfs9X\ +wB+0P/AMV3+3Z/wTq+E3/IK/4Vz/w1z+3P/b//AB/f2x/wpf4O6J+xT/wq7+yv3P8AZ/8AaX/Dyj/hJ\ +v7b+0z/AGP/AIUv/Y39kXX/AAkf9q6EAff9FFFABRRRQB8Af8EzP9J/Zd1jxFbf6R4f+IH7X/8AwUd+\ +LHgPXYP3uj+NvhZ8YP8Agol+1P8AFL4SfEvwjqceYPEnw/8AFPwy8X+E/EfhzWbJ5tO1vQvFGnavplz\ +dafe21xKfs8f8YjeO/C37C2s/6D8BbL4f+FNK/YG8b67/AKPdan4c8H6P40j8VfsU6hrEPnQeKfiB8M\ +Phl4D8M6z4W1XVp9O8VeOvhxrd00mn+MNd+EXxW+JGsn/BJ3/lFl/wTT/7MA/Y3/8AWdfhzX0/8a/gp\ +4V+OXhXT9C13UPEHhXxJ4V8QWvjn4WfFPwNdadpfxM+DPxM0vTtV0nRfiT8Nta1bSr+0s/EEOka9r+m\ +31jqVhqfh7xN4e8T634P8YaJ4h8G+IfEHh/VAD2CivzA+HX/AAUN1j+x5/gx47/Z9/aA+Lf7dnwk/wC\ +Ed+HX7Q/wi/Zh+AXju4+Cf/C7LfwJ4R8f+KJ/h3+1X8XNV0j4N+Evh/q/w38W6B8QPCuneOfizofi/w\ +D4RDxx4f0TXNIsfiTff8IXXoH/AAvf/goJ42/4mvwt/wCCfvw/+H/h+3/4l95o37a37a3hj4P/ABTud\ +Yi/0m41PQPDP7HXwS/aJ8MX3w/eyu9Pitb6+8a6Xrsuo2Wq2914WstPtdL1bWwD7/or4A/4Ux/wUc8V\ +f8SHx/8At3/s/wDg7wlf/wDIW8R/sufsGap8Nfjtp32X/TbD/hBvGv7S/wC198afBOi+dqdvZwan/bf\ +wz8S/adHutQtNN/sbV57DX9KP+HfHhzxV/wATD46ftY/t/wDx38Ww/wCh6d4u/wCGw/in+yb/AGd4cj\ +/f2nhz/hXX/BOi9+C3gnWvJ1O41e6/tvVPC1/4quf7Y+w32v3WkaboenaUAfT/AMa/2hfgF+zX4V0/x\ +1+0Z8cfg/8AAHwTq3iC18J6X4x+NfxL8F/CvwrqXiq+07VdYsfDOn+IfHWtWFpeeIJtI0LXLqKyjma5\ +kttGu50jMVvMyfMH/Dy39mfxH+7+CNl+0B+1R/av+h+APE/7Ln7Lv7Qnxo+BPxT8Rzf6HZeHPA37Yvh\ +z4c/8KS/5GXfomp63q3xI0nwr4V1ix1Cz8Za/4c/sbW5NO9g+Cn7EX7F/7NfirUPHX7Of7In7MHwB8b\ +at4fuvCeqeMfgp8AvhT8K/FWpeFb7UdK1i+8M6h4h8C+E7C7vPD82r6Fod1LZSTNbSXOjWk7xmW3hZP\ +p+gD4A/4aY/bT8bf8Sr4W/8E1/iB8P/ABBb/wDEwvNZ/bW/ac/Zi+D/AMLLnR4v9GuNM0DxN+x143/a\ +J8T33xAe9u9PltbG+8FaXoUunWWq3F14pstQtdL0nWz/AIQz/gpr8RP9L8RfHf8AZA/Zk8P+I/8AiX6\ +78O/hP8Bvif8AtMfFP4d6O3/Ep1PU/hp+1h8Uvi/4G8MeIviBcWUU+saNfeI/2eLjQvDuo6pbaVq/hb\ +x3p+kXF54i+1fHXjbwx8NPBHjH4jeNtT/sXwZ4A8K+IfG3i7WfsWoal/ZPhjwrpF5ruv6n/Z2k2k93f\ ++RpVhdy+TbQTXEvlbIYpJGVG/Mzxd/wU0s9A8L/ABU0zWfBnhn4VfF3w9b/AA18QeB9G8feOtN17wzZ\ +/C34teOdU8B2PxU+KeoaX/Zdr4ZuPCdzoGs3HirRodXPh641PUPCvg/w/wDEbUNf8baLsAPXv+GBf+E\ +t/wCS+/tqft//ALQH9n/8in/xkd/wx/8A8Il9r/5Dv/KNHwb8Dv8AhYn2/wCzaN/yOv8AwlH9kf2L/w\ +AU5/Yn9p69/a/oHwt/4J+fsO/Bfx3oXxb+G37Jn7P/AIf+Nvh/+057b9oKf4XeEvEH7R2q6x4g0fUNB\ +8WeLvF37RPibTLzxt47+IGu6ZrGuL4j8R63r2oa74jl8Qajc65qOoXOoXs0/DfsTftm6T+0nF438FeI\ +fFfw4174m+BNVknsdc+Gtrq+keBfi58PZtK8LXzfEf4b2Or6/rcVzpWj+KPE9z4T1+Cw8SeIW03V/Ds\ +F1qcukf8ACRaVpUej8Rv+Cmf7APws0S18QeJv2tPgtqdhearBo0Nv8OfFtt8YtcS7uLS+vY5rrwz8I0\ +1zUrHShDp1wr389pHYxTSQW8twk91bRzAH3PRX5TaF/wAFfP2efiB4yPhP4J/DP4/fHWwn0LUvEWkeO\ +fAWgfC7w/4N1zT9Au/D2meKLe1l+L/xc8L6lpeu6Xq/inQoL3S9U03T9TEOr2Wq29ncaHqWl6pe+ASf\ +8FG/28Pi1p5X4H/sofAX4Z2KarqVzpfxf+MHxy8QfFP4ZeP/AAxpGoahokcvgfwx8P8Awb4b8QfZ9Ym\ ++w6vomuXcaaZeaJaNcRwSjU9PnAB+7FFfzffCn9qH9tP45fF39pT4WfG/43XHw+vvhhcfDC21Twl+zV\ +aeDPD/AMMr/wAM/EzwEdQk0Xw/4o8a/C67+InhrVXh0q+uLvWbLxjaanb3fiR/7Bn0U6dZXLcx+1t8N\ +fhpbfs4/GzxN8Q7zWvHl/4e+E/xC/4QrxB8fvid47+NF34L8Tat4bvNP0b/AIV5qvxt8W60/gbXdR8R\ +t4dgH9jSWVxqd9Z6VHJ9pntbBYgD+miiiigAr4A/Y3/5OK/4Kxf9n/8Aw4/9dZf8E06+/wCvgD/gmn/\ +ybr8Rv+z/AP8A4Kxf+vTf2yKAPv8Ar4A8a/8AE4/4Km/s0/2R/wATX/hXP7AH7cP/AAsH+zf9O/4QT/\ +hdH7RX/BPb/hTv/CZfZd3/AAjH/CWf8KE+On/CNfbvI/t3/hS/iz+y/tX/AAjmsfY/v+vgD4c/8pTf2\ +yP+zAP+Caf/AK0V/wAFYqAPv+iiigAr5g/bd+Nfir9mv9i/9rv9ozwLp/h/VvG3wB/Zg+Pvxr8HaX4s\ +tdRvvCupeKvhX8KfFnjrw9p/iax0fVbC7vPD82r6FZx3sVrfWVzJbSSJBd28pWZPp+vgD/gqp/xMf+C\ +cf7Z/gCy/feLfjv8As/8Aj79lz4U6T/q/+Eq+O37WWlv+zR+z/wCBvt8u220P+3/jb8V/AGif2nqU1n\ +o+lf29/aWt6hpukWt7f2wB9P8A7PXwU8K/s1/AL4H/ALOfgXUPEGreCfgD8H/hp8FPB2qeLLrTr7xVq\ +XhX4V+C9F8C+HtQ8TX2j6VYWl54gm0jQrOS9ltbGytpLmSR4LS3iKwp7BRRQB8Af8E7P+Kg+HX7RvxY\ +1f8A0v4gfFv9v/8Ab4/4WFr/APx7/wDCQf8ADO/7U/xL/Yp+Dv8AxKrXZZaV/Y/7Mv7L/wAC/DP+g21\ +t/aH/AAg/9s6p9u8QanrGq6h9/wBfAH/BMb/iY/siaT4/sv33hL47/tAftr/tR/CnVv8AV/8ACVfAn9\ +rL9tj9oX9pf9n/AMc/YJdtzof9v/BL4r+ANb/szUobPWNK/t7+zdb0/TdXtb2wtvv+gAr59/aj+Lut/\ +A34K+IPiB4Z03StU8SHxN8L/Anh+PXRdzaJp2t/Fz4q+CvhLpPiPWdP0+5t59c0rSb/AMb2+qXGmQXm\ +nTapDpD6dHqmlvdLqNt9BV4L+058CbH9pX4IeNPg3feKNZ8FP4lk8LavpHizQHuk1Hw/4p8B+MvD3xC\ +8HamRp+o2N3Np0XivwroxvYrHUdL1Cay+0Rafq+k3rwalagH5UeO/+Cg37RvwJ8ceCdZ+K2o/DH4ieC\ +7bwt8S/HHj3wh8NfhjrXwvMnwq8BW3hc+NvEWkar4t+Kvi+61j4v6bqviPwa/hnTPtGieHdR0+88UWG\ +vXUN7c+Hta0D691n9vzUdQS9tfhl+zL8WtZu5pifC/ij4p6/wDDb4TfDXWtMS4WVNZ1mSx8V+IvHfg6\ +G70ZJZbKyvvh7/a8d5c2threm6GWvrjTv549T+CPx4+L3hjW/D2ifD/4o+EvGyTfFH4U654n+M3x5t/\ +iX8P/AAzq2lv4t+E/xh8F3eot8V/EPiC50BPEWl6slrJpGiJZ6p4g8G+GdXvopdMsIZIv2YoA6Lxn+0\ +X+1P8AEnTNW0a68K/sq+A/CGvaJfeGPEnw68Z+EviL+1HpnivTNUt7q01h9W8QyeKvhhajRL7TL9rGf\ +Qrjw3fx+XZyzy6tdR6h9g0/8s/iR8L1+HulXOkeIfiFpmheKtVPi74kWHxD0vXvHvhvUxZ6OtvpPiuL\ +UPEPin4uar4ybwza/D/W9K8K6veTeNDqE/hLWpNHXXbCC4UW36VVha74W8M+KP7H/wCEm8O6F4i/4R3\ +XdP8AFPh/+3dI0/V/7C8TaR539leItH/tC3k/szXbX7RcfZ7yDZcQ+e/lyLubIB+TviPS/E/jPwB4L0\ +3xF+z98VL74hWWj+GfGnw88LfFf4W23xE8Na94uuvDVzptho/xM1jwt4em8LaPplzqOp61pmo/8JFF4\ +S1HTLW+fWJNP8JXiadf2X278M9N8CaR8Qf2pfjRq2n+EtMaP4kS6a/xY1G10ayZPAngz4J/BfTPGGnv\ +47uY12+EtJ8d+EfFdvqURuvsdhq/hjUYrpYryyuVi8I/bS8X/Eoy+OrXwZrJ0Twv8C/g3bfFfxrY23j\ +H4keCdX8W3nxHg+L2geBr3RPEPwq8S6HqVpeeHfEvwlQT6beajPout6f8SL24urWHU/D2jST/AIg+G9\ +D13xLo02o2tg3iv40/DHxbbeOJ/E/hu8vfHXiLxD4ln1y88eadquqfEv4I/BTUNX1jUNQk1DU7SG7v/\ +idBeW+o6b5v2mwi0y0htfDjmOYYuvi6eX4GlLD4ao6Xtq9adPnlH3akqdKGHqOcKdVTpe9UpOc6c+W0\ +HCpL9JxHCvCGQYbJFxXxLjqeeZrgMNmc8Bl2XYXFxw+GxjqVMDQxOOr5rhVRxeLwUaGP5aWDxlPDYXH\ +YX2rni1icHQ/ZTxH+2B8JLD9s+DXj8U9I8ZfB3wV+yN4nvZdX+F2l3vxd03wv4p8S/F7wsfFN7r978J\ +9F1i60mzbQfBvhHz5dQZLCz2WmGt59SX7XwHwq/wCCkXwb+H3wh/Z9+Glh4Z8a+LfFMvws+HHgnSb7S\ +T4Xn8ODxlpHhjQfC1/p3ijS9G8Rah4y8LafbeK457SWQ+Dbq/vYLKXUPDml+ILSWwe+/MC+vPDGt/Ef\ +w/4+mvdN8Uz/ABI09NBv11rUPB/izxBL4i1IWmpeHNT1Xw74l8T/ABy8S3utXdvZvpcinRLCezn+wWp\ +kgNxeRy4+peDri18I+L/hD4i1bVdK/sXVT4o+HNh441jU/CumWumaqlxcaK2iJ8ZPix4AtZs6rF4o0/\ +U9Qh+H11JFJeX11CzfarSGLX6rm9W0a+bQowWt8NhlTqX7OWIq4uDhrqlSjO6TU0rxlyLPuAMFatlfh\ +/XzDES92VPOs6q4zCqD1lKnTybBcOYqOIUlFQqVMZVoKk60Z4WdSdKth/1V+Dn7bHijTv2ivEOgfED4\ +e+FPh94G+LviLxX8RfFGqap4t8WweJfB1h4R+EPwN8E6R4qg0Hxt8OfDl/qHgBb7wrrS6lenS1S1tjr\ +OvXdxpnhzwPrWpaj93ftb/DP/AIXV8FJ/g3/bf/CNf8La+Kn7O/wz/wCEj/s3+2f7A/4Tz9of4WeFv7\ +b/ALI+32n9q/ZP7V8/7N9qtvP8jyvtEO7zF/mv1b4g+I7DSfhh4t+Ht/pvgjW/A/h7WvHGreOtP8LeH\ +/DOiQa34tuPClpo+jeETpHwl0AP4vu/E/wj8TadJBp9nqytZQXtrdeJdR0C28Q/2X+5fwZ8S/ErUvhr\ ++wTo3hvwlYXvhT4j/tg/si6f4K8MaJFr/i3xN4I+A/gi88MfGO/stTvrWxtftEnhnVPhZ4jhGpzwXnl\ +eB9AtrzXry81tdU1pvNyarmVPG4+jisTUzPBVsRVjRrVFSU6fsKVCnUi1RpUabpSrKsk+RShWjOLc41\ +IKl9Hx7S4RxXD3B1TAZDg+BuL8Bk9LEY/A4WrjqlDMaeNzbM62FxT/ALQxWNr0cwhleJyatyRxU6GMy\ +3E0alPD4Krl+InmP9WdFFFfUn48FfAH/BLH/ib/APBPv9l74pXPyeIP2m/h/cftrePLOD5dH0j4p/t0\ +eJ9f/bF+LegeEbeTdPYfD/Tvib8cfFlj4ctb24v9RtNC07TrXU9V1fUIbnVLv7f8WeLPCvgLwr4m8de\ +OvE3h/wAF+CfBfh/WfFnjHxj4s1nTvDnhXwn4V8Oadc6x4h8TeJvEOsXMNpoPh+w0izvLq9vbqaK2tb\ +a1knnkSJGYfIH/AATJ8J+KvAX/AATb/wCCfPgXx14Z8QeC/G3gv9iD9lDwn4x8HeLNG1Hw54q8J+KvD\ +nwG8A6P4h8M+JvD2sW0N3oPiCw1ezvLW9srqGK5tbm1kgnjSVGUAH2/XwB+zP8A8Vt+2n/wUo+KWq/6\ +P4g+H/xA/Zi/Yp0az0/91o9z8LPg/wDsxeCP2xfDOv6nb3PmzzfECf4m/wDBRL412N9dRXEOnS6F4X8\ +LWtvpVrqFlq2qa39/18AfsPf8VB8Rf+CjfxY0j/S/h/8AFv8Ab/8AEn/Cvdf/AOPf/hIP+Gd/2WP2UP\ +2KfjF/xKrrZe6V/Y/7TX7L/wAdPDP+nW1t/aH/AAg/9s6X9u8P6no+q6gAff8ARRRQAV8Af8FLP+Tdf\ +hz/ANn/AP8AwSd/9em/sb19/wBfAH7cP/FQfEX/AIJyfCfV/wDS/h/8W/2//Df/AAsLQP8Aj3/4SD/h\ +nf8AZY/av/bW+Dv/ABNbXZe6V/Y/7TX7L/wL8Tf6Dc239of8IP8A2Nqn27w/qesaVqAB9/0UV8Qf8FN\ +vFnirwF/wTb/4KDeOvAvibxB4L8beC/2IP2r/ABZ4O8Y+E9Z1Hw54q8J+KvDnwG8fax4e8TeGfEOj3M\ +N3oPiCw1ezs7qyvbWaK5tbm1jngkSVFYAHP/8ABJ3/AJRZf8E0/wDswD9jf/1nX4c19/1z/hPwn4V8B\ +eFfDPgXwL4Z8P8AgvwT4L8P6N4T8HeDvCejad4c8K+E/CvhzTrbR/D3hnwz4e0e2htNB8P2GkWdna2V\ +lawxW1rbWscEEaRIqjoKACiivK/jr8TP+FK/BH4x/GT+xP8AhJf+FS/Cv4hfEz/hHP7S/sb+3/8AhA/\ +COr+Kf7E/tf7Bd/2V9r/sryPtP2W58jz/ADfs823y2APxG/Zd/wCTZv2df+yFfCP/ANQDw/XuteM/Dm\ +48DfCXQfhN+z1f/EbwneePPDvw28K+HtE0G81bR9F8XeLtM8IeHDo8viTS/BU2rzXpsJY/DGrzsITcx\ +wLYXKmeQW8rj2agAooooA/KH9vLXBo2l/tdQm8sNP8A7d/Zz/ZW0P7dqN14ktLeMz/Fj9qm9FnGfCkE\ +l1cX98bAafaxS7NNkutWhGsyLo/27P49X+oWuo+NPh58QWh0DxFe/EK10Twv4s0F9Q8F/EDWU1bWrWz\ +/ALFu7ex8beMvi34inuoZo7e2mml8M2V5DaaLBptvp0F9qMkA/UH9uC70e08CftCz6zLpsdnY/t0/Bj\ +VbyTU7S1vbaz0u0/Ze/Z6tNS1K5ju/h54lS309F1GCCeZ7FI2GpJaSf2l9rHh/Wvzc027ufE3h/wAa+\ +FNF0n4mePPhVrl3Jc+GtS+Fnhz4n/Frw1pN/qJ/tHW9Lfw/4V8W/Dvw/wCFLzT/ABWv9qWWmX3g2N1O\ +qQ3LWs2ltpl1ffMZbmeW4OliaWNzGhhassXjXGNWrTpy5frmItaMpJtc3Nrbuuh+x8XcE8acS55hsfw\ +7wlmfEGCpZLwnQlWwWX4rFUoVY8I5FUlRlUoUqkFVjGrGo4NqahUg2uWUW8G60vXdH0bx78Btc1fX/D\ ++mm1XxT8PYPFWveLPC2jXejTatHqcGlSR/F34ifD7R0tU8RWyRS3Z8GX93c3curahaWirZWzIWHi7Vr\ +Xw94I+MXhqyutI03Q7q78KfFCTwV4b1nwzDHDrDaTBdTanqfwa+Gvw+sUtUvbbSr6z0m58cahO0+saV\ +A0sCtftL754Z+CH7R91qeg3+k/C7Tfhd4l0bSrqHWdf1P4jeAfA3g3xZbX1vZw6nokmm/sr+DtI8RB3\ +1iDTdRsUvNWubS0XRJIZZppJv9I77S/2KPGmr/wBo3njHx18ONAHi3VbzUfGXh/w18LLL4iapGNQ8uy\ +1iXwx8ZPi/f3/iKx1i+soGvBdyxONP1TU557e3lCb5vR/taFTTC4DF4qpu4/V6mHtHrLnxiw1J2bS5Y\ +zdR3uoOMZOPzn/EPsThf3me8WcP5DhJe7Gt/bGFzbmqPVU/q3Dks6x0LxU5+3q4WnhY8ns54iNapQp1\ +fhX44WfgnRvFUesCD+39T8V/Dy21XTorS70qfQf7a1jxx8T9M13xTq/iTQfiP4mvPEmq28unRXFvFc+\ +JNYluNS1Evf6jbaZpSeFJ/wCmf9jLWPDWi+Jf+CSPgeO5+za94h0zVPGemaX5N/N9s07Rv2HfjGni3U\ +vtrRPDb+Xrfj/Qf3MkySP/AGt/o0TwwTeT/P8A/tWfs+3fwK8MWF74M13xV4l8LeKZrHS/G2r+IrK/1\ +fxPbWvh+20LTPCOkaz4x0nSIdL074ewPYaJBYaU6adLLqUNkxGtJZacvh3+l/8AZg+Cfhx/2vP2KbS7\ +TVdFl/Zx/Zk/aE8Q+ENI07ULee0GqWumfs7/AAPbSNduL2C7l1TSoPC/xI150MNzFO99p9nO93LAk8F\ +zz5FO1HEYerSlSxdLE4yc4TUeamsRiamJpxlKEpwfNSrU2nTnODcZR5ueEoxfiVRoyzvJ8wwOKhm2UY\ +vKMpw+Gx9GFWNDETyrK8DlONUI4inQxNLkxuDrRjTxWHw9epQVHFOiqGIoTqfvLRRRXvH58fAH/BWL/\ +lFl/wAFLP8AswD9sj/1nX4jV9/18Af8FOf+Jj+yJq3gC9/feEvjv+0B+xR+y58VtJ/1f/CVfAn9rL9t\ +j9nr9mj9oDwN9vi23Oh/2/8ABL4r+P8ARP7T02az1jSv7e/tLRNQ03V7Wyv7b7/oAK+AP+Caf/JuvxG\ +/7P8A/wDgrF/69N/bIr7/AK+AP+CVf/Ex/wCCcf7GHj+9/feLfjv+z/4B/aj+K2rf6v8A4Sr47ftZaW\ +n7S/7QHjn7BFtttD/t/wCNvxX8f63/AGZpsNno+lf29/ZuiafpukWtlYWwB9/0UUUAFfAH7TH/ABW37\ +af/AATX+Fulf6P4g+H/AMQP2nf21tZvNQ/daPc/Cz4P/sxeN/2OvE2gaZcW3mzzfECf4m/8FEvgpfWN\ +rLbw6dLoXhfxTdXGq2uoWWk6Xrf3/XwB8Rv+Upv7G/8A2YB/wUs/9aK/4JO0Aff9fAH/AAVO/wCJv/w\ +T7/ah+Ftt8niD9pv4f2/7FPgO8n+XR9I+Kf7dHifQP2OvhJr/AIuuI909h8P9O+Jvxx8J33iO6sre/w\ +BRtNC07UbrTNK1fUIbbS7v7/r4A/4KWf8AJuvw5/7P/wD+CTv/AK9N/Y3oA+/6KKKACvxy/a/0O1+Iv\ +7Wni7wH44vfEXif4b6R+zZ8AddT4Var4s8Uz/CLVdb8RfFX9p6DVNZ8VfCUawPDfjTVT/whXg+SC41j\ +S76azuPC2n3Vm8FzZ28sf7G1+Bv7Sfx00PwB+2F+0pY/EPTPiHqHjWO2+EGjfCzS9E+GHjS9h174KWf\ +wv0rxB4Ss9K8UWXh+Lw4mnTfHvxd+0XbJrGsarapHfjULHUtVt9N0W3j04A+XPjZ8PNE8NeMvhP8ADj\ +4TWOhfBuwPhz42fFzw/N8PfDWl+GrTRPjD4YX4S+A/Cfj670nw4lgniP7L4c+IfimzvdKvZH0vWrHUT\ +ZavbXcEduIfsP4XeNf+FlfDP4dfEX+zP7F/4T7wJ4R8a/2P9t/tH+yf+Eq8P6frv9mf2h9kg+3+R9v8\ +rzvIh83yt/lR7tg/Ob47ftDXlx4j0b4kwfDTxZ4Lk8DfBf8AaHsNAh+JLeC73TPFHja60rwL8TNE0EW\ +/wy+I+q3KWB0D4OeMJ7yWebTUEdokEF39ruIVr9J/AXg7TPh34G8F/D/RJ7+60bwL4T8OeDtIudUlt5\ +9TuNM8MaPZ6JYT6jNaWsEU1+9rYxNM0UMMbSMxSKNSEAB1lFFFAHwr8dfgH8OrTx9qvxj1bQ9N0DT/A\ +BZYCfxz8ZtM0jSbj4ifB3x34f0zw54e8CfEyx8S3dkbvTPhG3hLTdS0nxpZXE1/4ft4bTSNTvNG07RJ\ +vH2vScNb318+tT+Gb3w14r03xPb+ItR8MyaDL4e1LULt7qw0251yPU7a40SC6t7rw3daFbpdW2opMbQ\ +m7isZpINV8zT4/q34ofHX9m/wlZeMfCfxZ+KHwms1s9Av4vGfgHxP4k8NahrN3oWoaGb270i/+H81xN\ +fa4L7QbxfL09LG4l1CG/jigt5/PRHydE+MV1PpXwo0z4Qfs6ftk/Grw/440/w9Y+EfF2gfAn4rDw62j\ +albaJb+E/Efib4s/HldBs9Q0XUrLUoLn/hIrrV7y2aC3uNS1fUYInW5m8nC5c8DicbLBqnRwuOm68o8\ +uv1ib/eytHlTVSynzNuftHU5nODpxpfX8T8UYjivKuGZZpjcTiOIeGsLTymFSrKVbD1MowkU8tpxU63\ +tKFfAqdbCKNKMcLUwUcIlSpYjD1quL8Bt/BPxn1vRtdm0X4f/ANmazpmsz2mkp4lv7a00bxFp9rNZ39\ +vNHLc3NpqGlR3ukXBs5biTT5f7L1Nbl4rTXLOzhfU/QU/Z++JsvinTb0+M/CeneFGtZrfXtGfSdQ1++\ +aaCG+k0++8OXsf9ltpt1JeXVul+Lx9Rglt9PgFlDYTi5mvPorTfhV/wUc+INv45svDv7NXwc+BF1pN/\ +YR+CfEn7Q3x+tPFNv4o0y51O8M15J4J/Z88NeIWs7+PRrCMXVtc+ILKO2utetms7rWYra7UexeHf+Cf\ +37UviDX/BniH4pfto6R4O0aPw3bQ+Pfhh+z38APCen28viOTS7+W4k8NfFP42614uuZYbfxBeWcf2qf\ +w5bx6hpuiKq6RpF7dy3EPoezm/irS13SUUvRaOS/8AAr9ntb4n2VR/FXlruoqMV6L3XNL/ALfuujTtb\ +4fT9j3wnq/gfxB8P/H/AI7+IHjbQNfe4s5YX1W30C7tvDMsNnDF4WOuaTbDVdUsVW2lWa6v9RutQv4r\ +2WLUru8Ekpk+k/2KPD3xff8Ab61R/EOu/wDCbeAPhV+xTd6NfeK30zwv4dvE8bfGj9oC3uPDcmr6Vps\ +6T6j4g1PwL8AGGo3NhbwaGL/wfc3Vppnh6PVrXSjD8XvgP/wSV/Z/m1n4Q/t3ftv6Rd+LPiJIPicfB/\ +7YX/BQKz+DOr3/AIS1XWZLfSJNB+E/hf4ieBNFb4dxeMPCOuPpksXh544dQsLy2t7vytPt7Sx91+Gf7\ +SX7N/w//tvT/wBij/gnZ+1Xrvi3X/7NvPGnhH4Z/wDBPrxN+wl9u8OaF9vgs/Eet/EX9u7w38DPBPi/\ ++z9T11LW20Sy8U6n4qb/AISm4vtN0C40iz8QajpkQwlCFd4qMWq8oKm5Oc3zQT5oqScmpcrcnByTcOe\ +pyOPtJ83pwzDGQyt5L9YdTLfrCxUadS1T2df2fspzoTqKVSh7emqccTCjOnDFfV8JLExqyweFdH9U6K\ ++AP+Fz/wDBRzxV/wAT7wB+wh+z/wCDvCV//wAgnw5+1H+3nqnw1+O2nfZf9Cv/APhOfBX7NH7IPxp8E\ +6L52p295Ppn9ifEzxL9p0e60+71L+xtXnv9A0o/4UR/wUE8bf8AEq+KX/BQL4f/AA/8P2//ABMLPWf2\ +Kf2KfDHwf+KdzrEX+jW+ma/4m/bF+Nv7RPhi++H72V3qEt1Y2PgrS9dl1Gy0q4tfFNlp9rqmk630nGH\ +/AAUT/wCKg+HX7OXwn0j/AEv4gfFv9v8A/YH/AOFe6B/x7/8ACQf8M7/tT/DT9tb4xf8AE1utllpX9j\ +/sy/sv/HTxN/p1zbf2h/wg/wDY2l/bvEGp6PpWoff9fmB8Rf8AgnlrH9jwfGfwJ+0F+0B8W/27PhJ/w\ +kXxF/Z4+Lv7T3x98d3HwT/4XZb+BPF3gDwvB8RP2VPhHpWkfBvwl8P9X+G/i3X/AIf+KtR8DfCbQ/F/\ +/CIeOPEGt6Hq9j8Sb7/hNK+3/gp8a/Cvxy8K6hruhaf4g8K+JPCviC68DfFP4WeObXTtL+JnwZ+Jml6\ +dpWra18NviTouk6rf2ln4gh0jXtA1KxvtNv8AU/D3ibw94n0Txh4P1vxD4N8Q+H/EGqAB+0L8a/Cv7N\ +fwC+OH7RnjrT/EGreCfgD8H/iX8a/GOl+E7XTr7xVqXhX4V+C9a8deIdP8M2OsarYWl54gm0jQryOyi\ +ur6ytpLmSNJ7u3iLTJwH7EXwU8Vfs1/sX/sifs5+OtQ8P6t42+AP7MHwC+CnjHVPCd1qN94V1LxV8K/\ +hT4T8C+IdQ8M32saVYXd54fm1fQrySylurGyuZLaSN57S3lLQp4//wAFYv8AlFl/wUs/7MA/bI/9Z1+\ +I1ff9ABRRRQAV8AeCv+Jx/wAFTf2lv7X/AOJr/wAK5/YA/Ye/4V9/aX+nf8IJ/wALo/aK/wCChP8Awu\ +L/AIQ37Vu/4Rj/AISz/hQnwL/4Sb7D5H9u/wDCl/Cf9qfav+Ec0f7H9/18Afs8f8V3+3Z/wUV+LP8Ay\ +Cv+Fc/8MjfsMf2B/wAf39sf8KX+Dut/trf8LR/tX9z/AGf/AGl/w8o/4Rn+xPs0/wBj/wCFL/2z/a91\ +/wAJH/ZWhAH3/XwB+2R/ycV/wSd/7P8A/iP/AOusv+Cllff9fAH7Q/8AxXf7dn/BOr4Tf8gr/hXP/DX\ +P7c/9v/8AH9/bH/Cl/g7on7FP/Crv7K/c/wBn/wBpf8PKP+Em/tv7TP8AY/8AhS/9jf2Rdf8ACR/2ro\ +QB9/0UUUAFfjr/AMFevD3h7wn4B+FHx/Se18BanoXxK074e/E/4xt8O/F/xH07QPg5rHgn4n6no+n+P\ +/DHgjUbS41Tw/8A8LkXwJZ6PfXE8T6LqvjmeCwuYIPEOs2Wr/Rf/D07/gn3q/8Ao3wt/ah+H/7TfiBP\ +3954C/Ypg8T/ALdHxT0jR1/d3Hi7X/hJ+x1oHjnxP4d+H9vey6fZXXiO+0m30K01HX9K0y61GHUNX0u\ +2uz/hu7xH4q/4mHwL/YI/b/8Ajv4Sh/0PUfF3/CpvhZ+yb/Z3iOP9/d+HP+Fdf8FF/jh8FvG2teTplx\ +pF1/bel+Fr/wAK3P8AbH2Gx1+61fTdc07SgD8ULP8AZk8S/FnXpPhzrHwU/bx+PGh3nheLxR4y0bWPg\ +34O/Zi+CuoXVrq1tCdC0zxD8dLLwB4itbuz15tI1Kw0u08VajfvaQxC51HWYLXWcfZ+lfBr/gpv8RfC\ +D6hovwH/AGav2d/FFr4kayk0j47/AB48QfE241TQINMjnfUtOsPgT4CnsrSGfUb6KKGa510XUbaJeJN\ +pAiuLO8b7g/tL/gqb47/4lH/CG/sAfsr/AGb/AImX/Cwv+Fl/tFft9/2x5P8Aov8Awhv/AAp3/hU/7N\ +f/AAjX2j7Z9u/4Sb/hOtW+x/8ACPf2X/wid9/bP9saEf8ADJf7THjv/Tvjd/wUY/aA/wCJ7/ofj/4W/\ +sufDT9nv9mz4E6x4c/5Bl74c8Dah4j+Gvj342/Cf+1PDUSLqet6T8dP+Eqs9Y1TUNZ8G6/4O/4kljoQ\ +B4tZf8E4fjd4i8R+KZvin+3T4wXwF4h8N3WkWngn9n/4IfD34NapoGqXNvp1g2q6X8QvHuqeP9Xt4Ws\ +otZkZYpIb+K/1SK7sNUsYrOO0k+ffGnwc/wCCK3wU8YeHfhN+05+0r4P+OP7SPwZ1W01LTPhZ+0D+13\ +4h+Mf7TXiDxJ4ofSfHHhPwXpX7IvhbxuLv4k+K9e0q78GWmi+DtD+H95qHjW2m0awh0bxBeajEL77r/\ +wCHXH7Cesf8lY+Bn/DVH2b/AJAH/Dc/xN+MX7ff/CCed/yFf+FXf8NrfEHx7/wqf+1PK03+2/8AhGf7\ +J/t3/hHtI/tn7d/Y2lfY/r/4W/Cf4WfA7wJoXwt+Cnw0+H/wf+GXhf8AtP8A4Rn4dfC3wb4c+H/gTw7\ +/AG3rGoeItZ/sLwj4T0200/SPtfiDV9Vvrr7Pbx/aLzU7i6l3zzSOwB+dnwz/AGhvgj4C/tv/AIYe/w\ +CCZH7Vfif+1f7N/wCFn/8ACs/2L/CP7Af2H7D9v/4Qr+2/+Hgut/AP/hbPm/bPFv2b/hEf+Er/ALB+z\ +3H9v/2F/bOi/wBs+qf8Jn/wU1+In+ieHfgR+yB+zJ4f8R/8TDQviJ8Wfjz8T/2mPin8O9Hb/ibaZpnx\ +L/ZP+Fvwg8DeGPEXxAuLKKDR9ZsfDn7Q9xoXh3UdUudV0jxT470/SLez8Rff9FAHwB/wzP8Atp+Nv+J\ +r8Uv+ClHxA+H/AIgt/wDiX2ejfsU/sx/sxfB/4WXOjxf6Tb6nr/hn9sXwR+0T4nvviA97d6hFdX1j41\ +0vQpdOstKt7XwtZaha6pq2tn/DtL9mfxH+8+N17+0B+1R/av8Apnj/AMMftR/tRftCfGj4E/FPxHN/p\ +l74j8c/sdeI/iN/wpL/AJGXZremaJpPw30nwr4V1ix0+88G6B4c/sbRI9O+/wCigDx/4Kfs9fAL9mvw\ +rqHgX9nP4HfB/wCAPgnVvEF14s1Twd8FPhp4L+FfhXUvFV9p2laPfeJtQ8PeBdFsLS88QTaRoWh2st7\ +JC1zJbaNaQPIYreFU9goooAKKKKACvgD9of8A4xG8d+Kf26dG/wBB+Atl8P8AxXqv7fPgjQv9HutT8O\ +eD9H8FyeFf21tP0ebzoPFPxA+GHwy8B+JtG8U6VpMGneKvHXw41u1WPUPGGu/CL4U/DfWfv+igD4A/4\ +KZ/6T+y7o/h25/0jw/8QP2v/wDgnF8J/HmhT/vdH8bfCz4wf8FEv2Wfhb8W/hp4u0yTMHiT4f8Ain4Z\ +eL/FnhzxHo16k2na3oXijUdI1O2utPvbm3l+/wCvwB/aI/4sb+0d+xr/AMEr7b9z8H/20/2v/h9+0f8\ +AsgX+j/vdH/ZL+Fn/AATUuvg9+258af2Y5PB1/tnv/h/qPxN+B3hOy+G7WWt/2d4W0L9p3W/DOmeH/D\ +Hg/wCCfgbwz49/f6gAooooAK/GH4Q/thfBD4B/taf8FUvAvjNvjB4q8bXv7b/wu8WXfg74B/sz/tK/t\ +T+KvC3hXVP+CYf/AATo0fw74m+IXh79mP4SeL7v4Z+H9a1fw74ttfD974hh0y28RXPgXxFBocmoS+Ht\ +bWw/Z6vgD9of/jEbx34p/bp0b/QfgLZfD/xXqv7fPgjQv9HutT8OeD9H8FyeFf21tP0ebzoPFPxA+GH\ +wy8B+JtG8U6VpMGneKvHXw41u1WPUPGGu/CL4U/DfWQA/4a0/aY8d/wCg/BH/AIJz/tAf8T3/AEzwB8\ +Uv2o/iX+z3+zZ8CdY8Of8AITsvEfjnT/DnxK8e/G34T/2p4aidtM0TVvgX/wAJVZ6xqmn6N4y0Dwd/x\ +O77QviDxZc/8FJPit/wUk+AVnZ6N+xB+zL42+FX7EH7Xdz4h8Q6L4m+PP8AwUT8K2HhX42/Hn9iKLwd\ +o3xL8HReE/2Z7v4LeIPE2r/ATx1P4H1OfXfEFt4ntvgx8QrW10kS+G7y8tP3er4A+HP/AClN/bI/7MA\ +/4Jp/+tFf8FYqAD/hi74u+Nvl+PX/AAUI/a/+IHh/Xv8AiYePPhJ8J5/gn+yf8LLnWJf+JkumfDTx7+\ +z38ItI+Ofwu+H+m+KFtLjRrFPjfqmuy6dpFtofjDxT4z0+611dbP8Ah1j/AME+9X/0n4pfsvfD/wDab\ +8QJ+4s/Hv7a0/if9uj4p6Ro6/vLfwjoHxb/AGxdf8c+J/Dvw/t72XUL218OWOrW+hWmo6/qup2unQ6h\ +q+qXN39/0UAFFFFABRRRQAUUUUAFFfEHiz/gpf8A8E9PBfirxN8PNY/bY/ZgvPit4T8Qaz4M1T4JeE/\ +jV4B8e/H26+IWhajc6HffCvwz8BPAuuaj4y8afGB/ElrLpFl4Q0bQ7/xNqOtNHoun6VdarNDZvz//AA\ +31/wAJb/yQL9iv9v8A/aA/s/8A5Gz/AIxx/wCGP/8AhEvtf/IC/wCUl3jL4Hf8LE+3/ZtZ/wCRK/4Sj\ ++yP7F/4qP8AsT+09B/tcA+/6K+AP+Ez/wCCmvxE/wBE8O/Aj9kD9mTw/wCI/wDiYaF8RPiz8efif+0x\ +8U/h3o7f8TbTNM+Jf7J/wt+EHgbwx4i+IFxZRQaPrNj4c/aHuNC8O6jqlzqukeKfHen6Rb2fiI/4Zn/\ +bT8bf8TX4pf8ABSj4gfD/AMQW/wDxL7PRv2Kf2Y/2Yvg/8LLnR4v9Jt9T1/wz+2L4I/aJ8T33xAe9u9\ +Qiur6x8a6XoUunWWlW9r4WstQtdU1bWwD7/r5g+Nf7bv7F/wCzX4q0/wAC/tGftd/swfAHxtq3h+18W\ +aX4O+Nfx9+FPwr8Val4VvtR1XR7HxNp/h7x14ssLu88PzavoWuWsV7HC1tJc6NdwJIZbeZU8f8A+HX/\ +AOxZq/8Ao3xS+HXxA/ab8Pp+/s/AX7a37SX7Tv7dHws0jWF/d2/i7QPhJ+2L8Y/HPhjw78QLeyl1Cyt\ +fEdjpNvrtpp2v6rplrqMOn6vqltd/T/wU/Z6+AX7NfhXUPAv7OfwO+D/wB8E6t4guvFmqeDvgp8NPBf\ +wr8K6l4qvtO0rR77xNqHh7wLothaXniCbSNC0O1lvZIWuZLbRrSB5DFbwqgB8wf8PB/Dnir/iX/Av9k\ +79v/wCO/i2H/TNR8I/8MefFP9k3+zvDkf7i78R/8LF/4KL2XwW8E615Op3GkWv9iaX4pv8AxVc/2x9u\ +sdAutI03XNR0o/4Wr/wUc+IX7/wB+yF+z/8AAjwl4j/4luk69+1H+1Rqmv8Ax2+Gfmf8Sm/8ZeOf2aP\ +2aPgz4r8E+PvsOpx3mq6Z4Z0T9oWw/wCEm0ePT7bUvFngTV9Sv4PD33/RQB8Af8M8ft2eO/8AkrH/AA\ +UV/wCFc/2V/wAgD/hhj9kb4O/Bf+2Pt3/IV/4Wj/w2trf7Sn/CS/Z/sem/2J/wjP8Awhf2P7dq/wDbP\ +/CR/atK/sI/4dy/CLxT/p3x6+L/AO1/+034g1P9x48l+LP7WXxs8L/Cz4raOv8AoS+EfiX+yH+z34q8\ +DfAzxF8P7jwvFaaLrPhxPhfb6F4r06K5bxhp3iDUNX12/wBV+/6KAPAPgX+yd+yx+y//AMJT/wAM0fs\ +0/s//ALO//Ccf2J/wmv8Awov4N/Dr4Sf8Jh/wjP8Aa/8Awjf/AAlP/CAeHNP/AOEg/s//AISDXvsP2v\ +zvsn9t3nkeX9pm3+/0UUAFFFFABRRRQB8AfBH/AIxA+KfhL9jPU/8ASPgl8Uf+Fy+Nv2OvGEn/ABKbH\ +wB/YviNPiF4n/YY1S1uPI0i1/4Rrwl4x13UfgdpHhZIf+LNfBbxL4YuPC2kW3wWm8Y/EA/Zn/4rb9tP\ +/gpR8UtV/wBH8QfD/wCIH7MX7FOjWen/ALrR7n4WfB/9mLwR+2L4Z1/U7e582eb4gT/E3/gol8a7G+u\ +oriHTpdC8L+FrW30q11Cy1bVNb+n/AI7/AAU8K/tB/DPVPhl4t1DxBodtP4g8AeOfDXirwndada+KvA\ +fxM+EPxC8LfF34QfEnwyNd0rUNK1DxB4a+K3gbwZr9lY65peseHtRufDkdh4h0TWtEub/Srz8of2XPE\ +n/BSf4YfEX9uaz8a/8ABP8A/t74m/Hn9r//AIWB4A+NF5+0D8BfhT+xt4y8CfDH9lj9l39mKy+J/iOf\ +w58TviX8Xfgt/wAJrD+zT4k8TaJ4Qh+GXj688Oz/ABD0Dwtr/iSaC31vxhYAH7fUV8Af2b/wVN8d/wD\ +E3/4TL9gD9lf7N/xLf+Fe/wDCtP2iv2+/7Y8n/Sv+Ey/4XF/wtj9mv/hGvtH2z7D/AMIz/wAILq32P/\ +hHv7U/4Sy+/tn+x9CP+GLvi742+X49f8FCP2v/AIgeH9e/4mHjz4SfCef4J/sn/Cy51iX/AImS6Z8NP\ +Hv7Pfwi0j45/C74f6b4oW0uNGsU+N+qa7Lp2kW2h+MPFPjPT7rXV1sA+/6+AP8Ah6d/wT71f/Rvhb+1\ +D8P/ANpvxAn7+88BfsUweJ/26PinpGjr+7uPF2v/AAk/Y60Dxz4n8O/D+3vZdPsrrxHfaTb6Faajr+l\ +aZdajDqGr6XbXZ/w6x/4J96v/AKT8Uv2Xvh/+034gT9xZ+Pf21p/E/wC3R8U9I0df3lv4R0D4t/ti6/\ +458T+Hfh/b3suoXtr4csdWt9CtNR1/VdTtdOh1DV9Uubv7/oA+AP8AhuH4i+IP+Jv8J/8AgnJ+3/8AF\ +v4f3f8AyAPiF/wjf7LH7O//AAkH2f8A0XVf+LO/trftX/C/4m+D/smtQ6lY/wDFTeBdD/tD+zf7U0b+\ +0/D99pWsagf2l/wVN8d/8Sj/AIQ39gD9lf7N/wATL/hYX/Cy/wBor9vv+2PJ/wBF/wCEN/4U7/wqf9m\ +v/hGvtH2z7d/wk3/Cdat9j/4R7+y/+ETvv7Z/tjQvv+igD4A/4ZL/AGmPHf8Ap3xu/wCCjH7QH/E9/w\ +BD8f8Awt/Zc+Gn7Pf7NnwJ1jw5/wAgy98OeBtQ8R/DXx78bfhP/anhqJF1PW9J+On/AAlVnrGqahrPg\ +3X/AAd/xJLHQj/h1x+wnrH/ACVj4Gf8NUfZv+QB/wANz/E34xft9/8ACCed/wAhX/hV3/Da3xB8e/8A\ +Cp/7U8rTf7b/AOEZ/sn+3f8AhHtI/tn7d/Y2lfY/v+igDn/CfhPwr4C8K+GfAvgXwz4f8F+CfBfh/Rv\ +Cfg7wd4T0bTvDnhXwn4V8OadbaP4e8M+GfD2j20NpoPh+w0izs7WysrWGK2tba1jggjSJFUdBRRQAUU\ +UUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAU\ +UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQA\ +UUUUAFFFFAH/2Q==' $end 'DesignInfo' $end 'ProjectPreview' diff --git a/tests/system/extensions/load.json b/tests/system/extensions/load.json index 72a6a9dfd7b7..1a6d828880b5 100644 --- a/tests/system/extensions/load.json +++ b/tests/system/extensions/load.json @@ -1 +1 @@ -{"objects": {"MEMORY1": {"SurfaceMaterial": "Soft Rubber-Gray-surface", "Material": "Al-Extruded", "SolveInside": true, "Model": true, "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}, "SERIAL_PORT": {"SurfaceMaterial": null, "Material": "Al-Extruded", "SolveInside": true, "Model": "False", "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}}, "materials": {"PCB_Material": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 210, "Green": 105, "Blue": 30, "Transparency": 0.0}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.01", "mass_density": "2", "specific_heat": "2", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "1", "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0"}, "Al-Extruded": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 232, "Green": 235, "Blue": 235}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "200", "mass_density": "2000", "specific_heat": "900", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Solid"}, "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Opaque"}}, "air": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Electromagnetic", "Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 230, "Green": 230, "Blue": 230, "Transparency": 0.949999988079071}}, "permittivity": "1.0006", "permeability": "1.0000004", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.0261", "mass_density": "1.1614", "specific_heat": "1005", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0.00333", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Fluid"}, "diffusivity": "2.88e-05", "molecular_mass": "0.028966", "viscosity": "2e-06", "material_refractive_index": "1.000293", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Transparent"}}}, "boundaries": {"Memory": {"ID": 3, "BoundType": "Block", "IsComponent": false, "Objects": [62, 90], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": false, "Power Density": "2w_per_m3"}, "CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [422, 150], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "2W"}, "Source1": {"ID": 5, "BoundType": "Source", "IsComponent": false, "Faces": [155], "Thermal Condition": "Total Power", "Total Power": "1.5W", "Surface Heat": "0mW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "134": "CAPACITOR_1", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file +{"objects": {"MEMORY1": {"SurfaceMaterial": "Soft Rubber-Gray-surface", "Material": "Al-Extruded", "SolveInside": true, "Model": true, "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}, "SERIAL_PORT": {"SurfaceMaterial": null, "Material": "Al-Extruded", "SolveInside": true, "Model": "False", "Group": "graphics_card_simple", "Transparency": 0.0, "Color": [175, 175, 175], "CoordinateSystem": "Global"}}, "materials": {"PCB_Material": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 210, "Green": 105, "Blue": 30, "Transparency": 0.0}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.01", "mass_density": "2", "specific_heat": "2", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "1", "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0"}, "Al-Extruded": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 232, "Green": 235, "Blue": 235}}, "permittivity": "1", "permeability": "1", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "200", "mass_density": "2000", "specific_heat": "700", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Solid"}, "diffusivity": "0.8", "molecular_mass": "0", "viscosity": "0", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Opaque"}}, "air": {"CoordinateSystemType": "Cartesian", "BulkOrSurfaceType": 1, "PhysicsTypes": {"set": ["Electromagnetic", "Thermal"]}, "AttachedData": {"MatAppearanceData": {"property_data": "appearance_data", "Red": 230, "Green": 230, "Blue": 230, "Transparency": 0.949999988079071}}, "permittivity": "1.0006", "permeability": "1.0000004", "conductivity": "0", "dielectric_loss_tangent": "0", "magnetic_loss_tangent": "0", "thermal_conductivity": "0.0261", "mass_density": "1.1614", "specific_heat": "1005", "youngs_modulus": "0", "poissons_ratio": "0", "thermal_expansion_coefficient": "0.005", "thermal_material_type": {"property_type": "ChoiceProperty", "Choice": "Fluid"}, "diffusivity": "2.5e-05", "molecular_mass": "0.028966", "viscosity": "2e-06", "material_refractive_index": "1.000293", "clarity_type": {"property_type": "ChoiceProperty", "Choice": "Transparent"}}}, "boundaries": {"Source2": {"ID": 6, "BoundType": "Source", "IsComponent": false, "Faces": [451], "Thermal Condition": "Fixed Temperature", "Total Power": "0W", "Surface Heat": "0mW_per_m2", "Temperature": "30cel", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}, "Memory": {"ID": 3, "BoundType": "Block", "IsComponent": false, "Objects": [62, 90], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": false, "Power Density": "2w_per_m3"}, "Source1": {"ID": 5, "BoundType": "Source", "IsComponent": false, "Faces": [155], "Thermal Condition": "Total Power", "Total Power": "1.5W", "Surface Heat": "0mW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}, "CPU": {"ID": 2, "BoundType": "Block", "IsComponent": false, "Objects": [422, 150], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": false, "Use Total Power": true, "Total Power": "2W"}, "HTC": {"ID": 7, "BoundType": "Block", "IsComponent": false, "Objects": [134], "ParentBndID": -1, "Block Type": "Solid", "Use External Conditions": true, "Use Total Power": true, "Heat Transfer Coefficient": "5w_per_m2kel", "Temperature": "25cel", "Total Power": "0W"}, "Source3": {"ID": 8, "BoundType": "Source", "IsComponent": false, "Faces": [120], "Thermal Condition": "Surface Flux", "Total Power": "0W", "Surface Heat": "10kW_per_m2", "Temperature": "AmbientTemp", "Radiation": {"Radiate": false}, "Voltage/Current - Enabled": false, "Voltage/Current Option": "Current", "Current": "0A", "Voltage": "0V"}}, "general": {"object_mapping": {"12": ["Region", [80.0, 14.0, -55.0]], "10": ["Region", [-240.0, 14.0, -55.0]], "422": "CPU", "150": "KB", "178": "HEAT_SINK", "62": "MEMORY1", "90": "MEMORY1_1", "155": ["KB", [-153.6, 1.6, -102.0]], "451": ["ALPHA_MAIN_PCB", [-80.0, 0.0, -55.0]], "134": "CAPACITOR_1", "120": ["CAPACITOR", [-86.0, 13.600000000000003, -100.0]], "6": "Region", "34": "SERIAL_PORT", "118": "CAPACITOR", "450": "ALPHA_MAIN_PCB", "498": "Box1", "554": "MeshRegion1_SubRegion", "582": "MeshRegion2_SubRegion"}}} \ No newline at end of file diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index d13ff6e64f4e..9bf0c3bb7910 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -21,7 +21,7 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. - +from idlelib.browser import file_open from pathlib import Path import tempfile import pytest @@ -59,35 +59,36 @@ def test_successfull_json_export_import(ipk): @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) def test_successfull_data_loading(ipk): """Test the successful execution of the power map creation in Icepak.""" - extension = IcepakModelReviewer(withdraw=False) + extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] - assert len(boundary_table.tree.get_children()) == 3 - row1 = boundary_table.tree.get_children()[0] - row2 = boundary_table.tree.get_children()[1] - row3 = boundary_table.tree.get_children()[2] - assert boundary_table.tree.item(row1)["values"][5] == "4W" - assert boundary_table.tree.item(row2)["values"][5] == "5w_per_m3" - assert boundary_table.tree.item(row3)["values"][5] == "1W" + assert len(boundary_table.tree.get_children()) == 6 + rows = boundary_table.tree.get_children() + assert boundary_table.tree.item(rows[0])["values"][5] == "4W" + assert boundary_table.tree.item(rows[1])["values"][5] == "5w_per_m3" + assert boundary_table.tree.item(rows[2])["values"][5] == "1W" + assert boundary_table.tree.item(rows[3])["values"][5] == "35cel" + assert boundary_table.tree.item(rows[4])["values"][5] == "5w_per_m2kel" + assert boundary_table.tree.item(rows[4])["values"][7] == "30cel" + assert boundary_table.tree.item(rows[5])["values"][5] == "5kW_per_m2" + materials_table = extension.root.materials_tab.winfo_children()[0] assert len(materials_table.tree.get_children()) == 4 - row1 = materials_table.tree.get_children()[0] - row2 = materials_table.tree.get_children()[1] - row3 = materials_table.tree.get_children()[2] - row4 = materials_table.tree.get_children()[3] - assert materials_table.tree.item(row1)["values"][3] == 152 - assert materials_table.tree.item(row2)["values"][4] == "1.1614" - assert materials_table.tree.item(row3)["values"][5] == 2 - assert materials_table.tree.item(row4)["values"][6] == 0 + rows = materials_table.tree.get_children() + assert materials_table.tree.item(rows[0])["values"][3] == 152 + assert materials_table.tree.item(rows[0])["values"][4] == 2000 + assert materials_table.tree.item(rows[1])["values"][6] == '0.00333' + assert materials_table.tree.item(rows[1])["values"][7] == '2.88e-05' + assert materials_table.tree.item(rows[1])["values"][8] == '1.84e-05' + assert materials_table.tree.item(rows[2])["values"][5] == 2 + model_table = extension.root.models_tab.winfo_children()[0] assert len(model_table.tree.get_children()) == 11 - row1 = model_table.tree.get_children()[0] - row2 = model_table.tree.get_children()[1] - row3 = model_table.tree.get_children()[2] - assert model_table.tree.item(row1)["values"][2] == "air" - assert model_table.tree.item(row2)["values"][3] == "Soft Rubber-Gray-surface" - assert model_table.tree.item(row3)["values"][4] == "True" - assert model_table.tree.item(row3)["values"][5] == "Model" + rows = model_table.tree.get_children() + assert model_table.tree.item(rows[0])["values"][2] == "air" + assert model_table.tree.item(rows[1])["values"][3] == "Soft Rubber-Gray-surface" + assert model_table.tree.item(rows[2])["values"][4] == "True" + assert model_table.tree.item(rows[3])["values"][5] == "Model" @pytest.mark.parametrize("ipk", [AEDT_FILENAME], indirect=True) @@ -95,27 +96,37 @@ def test_successfull_data_modification(ipk): extension = IcepakModelReviewer(withdraw=True) extension.load_button.invoke() boundary_table = extension.root.boundary_tab.winfo_children()[0] - row1 = boundary_table.tree.get_children()[0] - row2 = boundary_table.tree.get_children()[1] - row3 = boundary_table.tree.get_children()[2] - boundary_table.tree.set(row1, column="Value 1", value="2W") - boundary_table.tree.set(row1, column="Selected Objects", value="CPU,KB") - boundary_table.tree.set(row2, column="Value 1", value="2w_per_m3") - boundary_table.tree.set(row3, column="Value 1", value="1.5W") + rows = boundary_table.tree.get_children() + boundary_table.tree.set(rows[0], column="Value 1", value="2W") + boundary_table.tree.set(rows[0], column="Selected Objects", value="CPU,KB") + boundary_table.tree.set(rows[1], column="Value 1", value="2w_per_m3") + boundary_table.tree.set(rows[2], column="Value 1", value="1.5W") + boundary_table.tree.set(rows[3], column="Value 1", value="30cel") + boundary_table.tree.set(rows[4], column="Value 1", value="5w_per_m2kel") + boundary_table.tree.set(rows[4], column="Value 2", value="25cel") + boundary_table.tree.set(rows[5], column="Value 1", value="10kW_per_m2") extension.update_button.invoke() assert ipk.boundaries[2].properties["Assignment"] == "CPU, KB" assert ipk.boundaries[3].properties["Power Density"] == "2w_per_m3" assert ipk.boundaries[4].properties["Total Power"] == "1.5W" + assert ipk.boundaries[5].properties["Temperature"] == "30cel" + assert ipk.boundaries[6].properties["Heat Transfer Coefficient"] == "5w_per_m2kel" + assert ipk.boundaries[6].properties["Temperature"] == "25cel" + assert ipk.boundaries[7].properties["Surface Heat"] == "10kW_per_m2" materials_table = extension.root.materials_tab.winfo_children()[0] - row1 = materials_table.tree.get_children()[0] - row2 = materials_table.tree.get_children()[1] - row3 = materials_table.tree.get_children()[2] - materials_table.tree.set(row1, column="Thermal Conductivity", value="200") # Al-Extruded - materials_table.tree.set(row2, column="Viscosity", value="2e-06") # Air - materials_table.tree.set(row3, column="Mass Density", value="2") # PCB_Material + rows = materials_table.tree.get_children() + materials_table.tree.set(rows[0], column="Thermal Conductivity", value="200")# Al-Extruded + materials_table.tree.set(rows[0], column="Specific Heat", value="700") + materials_table.tree.set(rows[1], column="Viscosity", value="2e-06") # Air + materials_table.tree.set(rows[1], column="Diffusivity", value="2.5e-05") + materials_table.tree.set(rows[1], column="Thermal Expansion Coefficient", value="0.005") + materials_table.tree.set(rows[2], column="Mass Density", value="2") # PCB_Material extension.update_button.invoke() assert ipk.materials.material_keys["al-extruded"].thermal_conductivity.value == "200" + assert ipk.materials.material_keys["al-extruded"].specific_heat.value == '700' assert ipk.materials.material_keys["air"].viscosity.value == "2e-06" + assert ipk.materials.material_keys["air"].diffusivity.value == "2.5e-05" + assert ipk.materials.material_keys["air"].thermal_expansion_coefficient.value == '0.005' assert ipk.materials.material_keys["pcb_material"].mass_density.value == "2" model_table = extension.root.models_tab.winfo_children()[0] row2 = model_table.tree.get_children()[1] # SERIAL_PORT From 355c0c4a7431a25f0d92dc4889c70eb463106911 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 11:01:50 +0000 Subject: [PATCH 45/50] CHORE: Auto fixes from pre-commit hooks --- .../extensions/icepak/icepak_model_reviewer.py | 1 - .../configuration_data_processing.py | 2 +- .../extensions/test_icepak_model_reviewer.py | 15 +++++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py index 787c5df744ee..2d02b9c149f2 100644 --- a/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py +++ b/src/ansys/aedt/core/extensions/icepak/icepak_model_reviewer.py @@ -212,7 +212,6 @@ def update_cell_value(self, row_id, col, new_value): self.rows_data[idx][col] = new_value def edit_cell(self, event): - region = self.tree.identify("region", event.x, event.y) if region != "cell": return diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py index 9be98ca91c52..97c198424d8a 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/configuration_data_processing.py @@ -75,7 +75,7 @@ def extract_boundary_data(data): [boundary_name, boundary_type, selected_objects, bc_name1, value1, bc_name2, value2] ) read_only_cols.append(cols) - if not( use_external_conditions or use_total_power): + if not (use_external_conditions or use_total_power): bc_name1 = "Power Density" bc_name2 = "N/A" value2 = "0.0" diff --git a/tests/system/extensions/test_icepak_model_reviewer.py b/tests/system/extensions/test_icepak_model_reviewer.py index 0a007bc7c802..1aed64c5d146 100644 --- a/tests/system/extensions/test_icepak_model_reviewer.py +++ b/tests/system/extensions/test_icepak_model_reviewer.py @@ -21,7 +21,6 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from idlelib.browser import file_open from pathlib import Path import pytest @@ -79,9 +78,9 @@ def test_successfull_data_loading(ipk): rows = materials_table.tree.get_children() assert materials_table.tree.item(rows[0])["values"][3] == 152 assert materials_table.tree.item(rows[0])["values"][4] == 2000 - assert materials_table.tree.item(rows[1])["values"][6] == '0.00333' - assert materials_table.tree.item(rows[1])["values"][7] == '2.88e-05' - assert materials_table.tree.item(rows[1])["values"][8] == '1.84e-05' + assert materials_table.tree.item(rows[1])["values"][6] == "0.00333" + assert materials_table.tree.item(rows[1])["values"][7] == "2.88e-05" + assert materials_table.tree.item(rows[1])["values"][8] == "1.84e-05" assert materials_table.tree.item(rows[2])["values"][5] == 2 model_table = extension.root.models_tab.winfo_children()[0] @@ -117,18 +116,18 @@ def test_successfull_data_modification(ipk): assert ipk.boundaries[7].properties["Surface Heat"] == "10kW_per_m2" materials_table = extension.root.materials_tab.winfo_children()[0] rows = materials_table.tree.get_children() - materials_table.tree.set(rows[0], column="Thermal Conductivity", value="200")# Al-Extruded + materials_table.tree.set(rows[0], column="Thermal Conductivity", value="200") # Al-Extruded materials_table.tree.set(rows[0], column="Specific Heat", value="700") - materials_table.tree.set(rows[1], column="Viscosity", value="2e-06") # Air + materials_table.tree.set(rows[1], column="Viscosity", value="2e-06") # Air materials_table.tree.set(rows[1], column="Diffusivity", value="2.5e-05") materials_table.tree.set(rows[1], column="Thermal Expansion Coefficient", value="0.005") materials_table.tree.set(rows[2], column="Mass Density", value="2") # PCB_Material extension.update_button.invoke() assert ipk.materials.material_keys["al-extruded"].thermal_conductivity.value == "200" - assert ipk.materials.material_keys["al-extruded"].specific_heat.value == '700' + assert ipk.materials.material_keys["al-extruded"].specific_heat.value == "700" assert ipk.materials.material_keys["air"].viscosity.value == "2e-06" assert ipk.materials.material_keys["air"].diffusivity.value == "2.5e-05" - assert ipk.materials.material_keys["air"].thermal_expansion_coefficient.value == '0.005' + assert ipk.materials.material_keys["air"].thermal_expansion_coefficient.value == "0.005" assert ipk.materials.material_keys["pcb_material"].mass_density.value == "2" model_table = extension.root.models_tab.winfo_children()[0] row2 = model_table.tree.get_children()[1] # SERIAL_PORT From de66aa8baaf712aadea5b9150c2d85678a6c9153 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 29 Jan 2026 12:12:22 +0100 Subject: [PATCH 46/50] reformatted long line --- tests/unit/extensions/test_icepak_model_reviewer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index bcc4d439e3c4..d6df219a4535 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -190,8 +190,6 @@ def handle_toplevel(): table.edit_cell(event) tree.update() # Verify the result (comma-separated string) - # Note: Ensure these expected values match your multi_select_options - # expected_val = f"{table.multi_select_options[table.headers[3]][0]}, {table.multi_select_options[table.headers[3]][1]}" assert tree.set(row_id, "#4") == "CPU, DDR" From c500734b27fbafe7ea245466f2bd5cca3386a8fa Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Thu, 29 Jan 2026 12:19:13 +0100 Subject: [PATCH 47/50] codespell fix --- src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py index 8f47a4e809dd..b97ca1f92901 100644 --- a/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py +++ b/src/ansys/aedt/core/extensions/icepak/model_reviewer/backend.py @@ -47,7 +47,7 @@ def import_config_file(aedtapp, json_data): out = aedtapp.configurations.import_config(full_path) result = aedtapp.configurations.validate(out) if result: - aedtapp.logger.info("Sucessfully imported configuration") + aedtapp.logger.info("Successfully imported configuration") else: aedtapp.logger.info("Import has issues") return result From 5efc9fa4512126771c8b314d94e45caf6f68dd50 Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 30 Jan 2026 09:27:58 +0100 Subject: [PATCH 48/50] removing UI unit test as it is not working in CI/CD --- .../extensions/test_icepak_model_reviewer.py | 106 ------------------ 1 file changed, 106 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index d6df219a4535..8a08f6250785 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -86,112 +86,6 @@ def flatten_list(data): return data -# --- Pytest Fixture --- -@pytest.fixture -def table_app(): - root = tk.Tk() - root.geometry("800x500") # Set a size so it's visible - # root.withdraw() - # --- 1. MOCK DATA --- - headings = ["Name", "Type", "Objects"] - type_list = ["text", "combo", "multiple_text"] - selection_dict = {"Type": ["Solid", "Fluid"], "Objects": ["CPU", "DDR", "RAM"]} - row_data = [["BC1", "Solid", ["CPU"]]] - read_only_cols = [[]] - - # --- 2. CORRECT LAYOUT --- - notebook = ttk.Notebook(root) - notebook.pack(fill="both", expand=True) # Must pack the notebook! - - tab = ttk.Frame(notebook) - notebook.add(tab, text="Mock Tab") # Must add the frame to the notebook! - - table_data = (headings, type_list, selection_dict, row_data, read_only_cols) - table = add_table_to_tab(tab, table_data) - - # --- 3. PROCESS EVENTS WITHOUT BLOCKING --- - root.update_idletasks() - root.update() - # root.mainloop() - # We do NOT use root.mainloop() here because it blocks pytest. - # root.update() is enough to render the window for the test. - - yield root, table - - root.destroy() - - -# --- Main Test Case --- -def test_ui_edit_workflow(table_app): - root, table = table_app - tree = table.tree - row_id = tree.get_children()[0] - tree.see(row_id) - # ========================================================== - # 1. TESTING THE 'TEXT' COLUMN (#2) - # ========================================================== - # Locate cell, simulate click, and type text - x, y, w, h = tree.bbox(row_id, "#2") - event = tk.Event() - event.x, event.y = x + 200, y + 20 - table.edit_cell(event) - - # Find the Entry widget that was dynamically created - entry = next(c for c in tree.winfo_children() if isinstance(c, tk.Entry)) - entry.delete(0, tk.END) - entry.insert(0, "BC2") - tree.update() - entry.event_generate("") # Simulate pressing Enter to save - assert tree.set(row_id, "#2") == "BC2" - - # ========================================================== - # 2. TESTING THE 'COMBO' COLUMN (#3) - # ========================================================== - # Locate cell, simulate click, and select from dropdown - x, y, w, h = tree.bbox(row_id, "#3") - event.x, event.y = x + 200, y + 20 - table.edit_cell(event) - - # Find the Combobox widget that was dynamically created - combo = next(c for c in tree.winfo_children() if isinstance(c, ttk.Combobox)) - combo.set("Fluid") - combo.event_generate("<>") # Trigger selection event - tree.update() - assert tree.set(row_id, "#3") == "Fluid" - - # ========================================================== - # 3. TESTING THE 'MULTIPLE_TEXT' COLUMN (#4) - # ========================================================== - x, y, w, h = tree.bbox(row_id, "#4") - event.x, event.y = x + 200, y + 20 # Adjust to hit the cell - - def handle_toplevel(): - # 1. Find the Toplevel window - # We look for a Toplevel that is a child of the table - top = next(c for c in table.winfo_children() if isinstance(c, tk.Toplevel)) - - # 2. Find the Listbox inside that Toplevel - listbox = next(c for c in top.winfo_children() if isinstance(c, tk.Listbox)) - - # 3. Select specific indices (e.g., first and second items) - listbox.selection_clear(0, tk.END) - listbox.selection_set(0) - listbox.selection_set(1) - - # 4. Find and click the 'OK' button - ok_btn = next(c for c in top.winfo_children() if isinstance(c, ttk.Button)) - ok_btn.invoke() - - # Schedule the handler to run once the mainloop starts waiting for the window - table.after(100, handle_toplevel) - - # This call will block due to self.wait_window(top), - # but the after() scheduled above will execute. - table.edit_cell(event) - tree.update() - # Verify the result (comma-separated string) - assert tree.set(row_id, "#4") == "CPU, DDR" - def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" From 75057dd86751eea974a6c8d69f96c4cc38100311 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 08:29:16 +0000 Subject: [PATCH 49/50] CHORE: Auto fixes from pre-commit hooks --- tests/unit/extensions/test_icepak_model_reviewer.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/unit/extensions/test_icepak_model_reviewer.py b/tests/unit/extensions/test_icepak_model_reviewer.py index 8a08f6250785..9f493e36f5a3 100644 --- a/tests/unit/extensions/test_icepak_model_reviewer.py +++ b/tests/unit/extensions/test_icepak_model_reviewer.py @@ -25,15 +25,12 @@ import json import os from pathlib import Path -import tkinter as tk -from tkinter import ttk from unittest.mock import patch import pytest from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import EXTENSION_TITLE from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import IcepakModelReviewer -from ansys.aedt.core.extensions.icepak.icepak_model_reviewer import add_table_to_tab from ansys.aedt.core.extensions.misc import ExtensionTheme from tests import TESTS_UNIT_PATH @@ -86,7 +83,6 @@ def flatten_list(data): return data - def test_icepak_model_reviewer(mock_icepak_app): """Test instantiation of the IcepakModelReviewer.""" extension = IcepakModelReviewer(withdraw=True) From b7c2eaf5cee75b3bd878b0c1e8f0a49fab6f810c Mon Sep 17 00:00:00 2001 From: siva-krishnaswamy Date: Fri, 30 Jan 2026 10:34:34 +0100 Subject: [PATCH 50/50] doc correction --- .../pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst index 9bbf18e363c2..893238907b08 100644 --- a/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst +++ b/doc/source/User_guide/pyaedt_extensions_doc/icepak/icepak_model_reviewer.rst @@ -1,4 +1,4 @@ -Icepak Model Reviewer +Icepak model reviewer ===================== The Icepak Model Reviewer extension allows users to inspect and modify details of an Icepak project. It enables