From 86a73fd3add4f771fc5347d7bcc4921b2a410ad3 Mon Sep 17 00:00:00 2001 From: jngan Date: Thu, 24 Nov 2022 18:32:04 +1100 Subject: [PATCH 1/3] docs: example.ipynb * modify content of example.ipynb * add ospgrillage example to example.ipynb * add example to tests --- calabru/calibrator.py | 2 +- docs/source/images/osp_example.png | Bin 0 -> 56827 bytes docs/source/notebooks/example.ipynb | 249 ++++++++++++++++++++++++---- tests/fixtures.py | 144 ++++++++++++++++ tests/test_updating.py | 28 ++++ 5 files changed, 387 insertions(+), 36 deletions(-) create mode 100644 docs/source/images/osp_example.png diff --git a/calabru/calibrator.py b/calabru/calibrator.py index 083afb1..9a999de 100644 --- a/calabru/calibrator.py +++ b/calabru/calibrator.py @@ -176,7 +176,7 @@ def update_model(self, **kwargs): # response error e_response = np.sqrt( sum([resp**2 for resp in self.global_resp_diff]) - ) / np.sqrt(sum([target**2 for target in self.target_response_list[0]])) + ) # parameter estimation error error = np.sqrt( sum([estimates**2 for estimates in param_increments]) diff --git a/docs/source/images/osp_example.png b/docs/source/images/osp_example.png new file mode 100644 index 0000000000000000000000000000000000000000..325631db9b8591915ace8fc1c9db4b4fd0b80cf4 GIT binary patch literal 56827 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%0ASN6Po6~SR`h~_Ver&M zHl}GORlUr_IA}(*dTL!nN=lQ3@}-5aT-E{ zd~07{i1zeu?@bwIyBpQKh1M{^cYsV@5;VgyZWWZK`KA% z;lq^bnpgPdHi48ty*m$=2!4KTCT?nK3SLf^hU8RTz`F4>yDp}U>Dr+bO8%LM#UoND zmd74Gy)svnmjG5iZr6n7tm*h;g)k9>9nQ4+L!n_jH%nCv{ewbL30OpFq*6J|z6ykz z+FcKuq=xYa$~CYXRkpk2+y)3~1US4`5ATO>4qKX<;e{VV!+mb z0$u%fvdoLOAFCGjLr zzIcV$ov3MbL7lxa?iRCJ&odIuY3YxkSyxW=IMxTRE|LAXK^=A8dtHPEfQ+b;l2XNC z=#ShHZeZ8fn!N@-KEJl;BeVU%+|FUXGaQgqU*NRO#d|LG*C*Hjb$|x!2w5O_0vS0u z{Meo-KvdwL1b@hoAw3y%MFA5Z(xA49OBH&BJ0E$jh=gfAeM*8No&mTEkmL2p2piYB zi;GLd?PbJkW4{*|#{SFb+DE)Aad9nN-M4>I+`j}N2JF#>N0GaSJIfrg1If;MdV24~ zDW^mqSv-N6u>$r;j6o%maA|04%*xAKzbfo#VevrgHy&nkt)l{Hb#Sj?fr?Swekze) z>r{E@At)rI37yCkynw-=9Kiq#@l&%m^V!LoGI?_ez=@(k^*6#&eH zK#P`^9Le;BEb3UCt3=J&ZwB29tm(*(w$6X2p5$VwS~%~kx8exO`hRJO;UkWNv%sLB z^7?vG5Vh5LB zKYLVlGctZ+mQDr~p>eqlfr7w~mZ&IL)bFRK%S%f!GL-)EFok?)h0ITROA8Ia#ZRsN z+|ZN@J60#0Irjq5Y2$G|gWtguRY;k!nODvq)10gU-PWx7!@4Rr$y#0^drX=G%Cf_PWt$uhG{@HPvQ zAuZMOtTb%h?Tgz4M7B~_IDed&>ifu@(2ke|Q5?`+_-1LSXt zBhO@^z3ScGG9ju!wb}FDrGZrF&*+pCd_WStweKG{=Xc7F%0VGJ4c$?#ot95`+5Ony z_41|1VNC5Wy8n~_ZEbB7%J{jbSl+v-DK(~mmPAIoaqb&ee`G*0Vu3aGCW;~yR}gWw zLH)RX;|2`hZI2bo1C1pq%1Cxi^TS_s5H$Pn;X}*Ow|u}eh!qG#+7UXe<@C>2XgCqK zaRy-82!UBE3Kar6SSXcS#bnw(OT*Q;@SE!|cr*Zt`nRgYvfEMngkG!Jt^H)yILsL4);gZ0e+BOAn*EB@g*2@E<*X zeD}A`c>aBPyL;Lk07{Eq?1Nli`E$~<@EOJ%HV48S>^vhj&9gW}`}Uqw0I~OP6K#vZ zZ@@YjiYA~D^gnoT9s&6P0kEu6sRVm%f@b5vzxesN@#68HUwvn%$H;Y8*nQ1z(dc^V zW364rk00(3&N84C#gWVXK`?Xd`{%RUGRTgwat{A|^`3b5E-E1b=VbSO7Y8v$0mfh8 zI$Y_0Fd0i*zZCg?xQi3p<1{K)nw)7=X@TWrv)O)IR=NVo07*)M9dtKoMI8#Q>}HeI z4Zd74N%W0r86YVytOP;J({a#e>GZ7W{q*%KLH4lviT0@rAGz=ICIL^FC~$_LMa z3_N5gY<3=d&G-&6z8)Tq*5>F1S_rhZ;IF9c1>UqyualZ{AwZRv?+Xoppzb?u6SN58 zCy0wEIyyQd6O&kK+h7dXt{@>iN~#1?=236C5f8+zAHR5(nw}mH&V@7I)z@xmJyf3c z7J8FUyN7@42(fo77q7(Ks_Kqwpf{zlV zbav>3WO2bMp`@gQp*0AAACiqLQ(M%j1LXM2>T5|TBMXZpX#bgr<6ktiv^{V;u3Wp8 zihv?WJ%W*H(d15PIS-4rP)fsa%6*PvK6q69TnZfMd};4N;6G5Nz_qnW-+D*R z-KFX0CkERg5#+?2`}dFAaqN7Wo-IpR)?B&{y#}2EK}r~es*JlEm(T_k2_ZJXKU;V) zlwGmF-{<3bMlQH{vblXaC;!@m3e}*OxcdG&OOMN^J6&4%rXb{4zwNt#DKb;Q03K+pkAQ z`z}e(K=LpJbR-HyLaePF0+pC3OFORBf6Wo({pPt4{+iCeKT0x`m;2_OWk+8D;)e9= z5{UAw6Zq1hVx~f>H2@>|uxd@G(@@jrArNK(S$Y9*TQ{gP7vYYlgrj@dGZbPFu?BfU zP-?0&ZKfG}k5{mgRTL`X&{rKjZlfyp@xK7`IwEXuLJOgJ z)wP`|?d=Nfdy|)uX$byF9n|s(s09NcuXCNAp46K_jvQQDkf#$M)&e0w*q0q&Bp?b1 zc*3i7l?pU6c|@Q(1D0YBGR&v0NM)h6pJJY~uP6~+kK9lp8s4KmpOFdW{9%l8v3#rb z9k_gsYvYB8HI5`@mCtrE;I;zn?LmeBIDg3BZVTGtT8l1?nSWGt_ihZJ8f5jrF8#i_ zIoK0>5mH5V2x`+T7hRcWEY(b#5=;wgIhzJ52ofjA{bf&{;6fMzYO6onP$?NyoSA?r zedtfScOQ2E%P+-K+v0xuX&zZhT238@2nzRFe)~(=jouR^7^W_qALYp&E=chPXUi9q zx24I;!toH!0=-Q~!KAkJ8y!jobbe67uh`h6yNuqG)ySTqbpm1yDPdrM$+cC&Ek#F~ z>gt&um@MeY+1Yf+bL6^-=Gj~HkcY6Xg zqj=An)fyH&a*sguFYWAPIzHIqo`0?aC@^MJsEts#V~_0C<_zuj{1$;JO$Q4FY5A~o zj9GO&#FK4pnIN)c54n{;oNI0KK68&ZrD*Fd(sKFD9al$kgSUGw`a+-|cm*=^4yTIG z;%wS(u}Vo%0W(2R(ABGyHwdnKduu@w3ifdrm4?@)Y{e&_nk~RhM}7=YA5@W~FJG*X zMRu?`yCUh6TLX*WVIBUb`6SWIb<52lO1O>S4;;*e3d0Eavo)WA4EQzW^BzP#ZnZW@ z3FhPHH}HF+sXkfGX9_WB-v2rcA5O$f_S3N!R)576=-uZ{9M8?_E(iT!;m}aRJuT*ZH%A z;*%BbO4C<=*}QtfN*2#IkpN8O*^vzR4lpZWfC1FFVrQ4}>uYoN^*j$e%SPAqx2H8G z&t1xj4V^8gCniXJV1H?*p(#DP!(+Rexmf3R2kE^RV0iQ(I`I3A;L&HKgDQoh7otxm z)Bi8svr>>S&rS6shB>0YU$N(_r&KMz0;oQ^y1I1`k+t?4=KQxlfh%e;hf{zkfGk`{ zD%3d+;3Gc;q8K3m%Zaa@RMQ+l!RwYPh+&594s!=@bsYRtiKYydH6V-y*DC=ri>_V; zm9STMYs~1S1Z;Q;3W^d4;7iYkiGvn~Y#-xafA4plV1rn77=(mmSCF1wb zy}UH8@LR7rn-;Bzd3Rp3=PCuH-D;({?zv1r``x=o1tE3>n}S#giv+ouw&D9%{{fDJ ztszQt>uA`v0PA8*UkSl^m-6F{s^4R#^vy8&Zr_$286DkON)>j5HGl-7Atrscov3U- zU1PJNh^NxR9*ItXa>)8Ld?fcZHW-)>~Kig5qX%W2qd-NDxWKW^wDmW z(N!z{4jML{CZ6w;wQG`H-pzW87&_4i(8-ZF@I4_L-Lp4~U^+%)9`-SxMb+2W-w=VI=;-3U%waA;#tzf(}?;N8=8~v*h?Lno0=}bVD$Ohh-d)7p%BNo zGEfeVUkERBUhjM?b<{}udv`bU?p?9f`_k_P*}@!Fw9-r#b(G6MqdvI9zpJCKKXBFD zCLVbLIFwNw@t0RN{{$qb6u6zp{_9J)^hhP4&F$o3ZnEYPYK}hn+Hi52X8+;o)s-+YVPWA%Wy|9YcP_UXI9qb7V>nux)w!k3985MH zay{sMVqArYl9kG-kk$9}{K*^1u{5cR( zWFzOf6(xg=@j#CYFkr7&GqPr$JtG9&lnFwPJ7d!GnR#i_bHQ-rW}r8oAXyuyyhqWZ z_+o+sV9;$C^%RK33KI(v)hBC+6}C~Et!qq>JIK85H}+7HHDmk`=Zkf1ZM91woFaix zGQcYPZ(@F1`6TgK*XXD!?NEGZ*A4FbH;#T8A4e z4SCX?v*WFD(2*kn-0Z;9XH%?z;~vW>e~U#@GH|jfSgmB>wd4p{vibw%NTqLYi!-iy zcTfVoMYw#DQRkm89>DX#TbR4Ob~{Xofv4rY^nAlO#9iv^C)NpzQ@JXq8t%+*@k+oc z77(ObrJ;NY`{Jx=4z}i*CpYx5pb2*RwP(DV;Yl&Um{NMHxnd{$o|HYPFbLL`W;v&9Ie)xd!WN9aR9-k7Ko zcr!@DY&>t?23WONRau0F9{gBibNQ*w(T!E3?lD16NDh^0q_R+@>U?P`FYl|OlX?%s zGK1zQYajGo)VrjtCEDx?Da(5r-rmAhWxw5|%DATqa89&q0QaG`zvX+QpPMZg2F>-r zQudy_1(ZMf61|lD@?biwx3L_%vMM;_mzkHB4C|A&IBXa1;lqbMaMFoPe{-%QKPea_ zMMPRKHC^H0fcpY+1o%ym)ldi6$3Zrnvn32EDMTFPEoiV1fOBQ=1&D`xYy(+z;KFYM zHMO_5M}dun?3$w6-)NDm04<`bAT$^>Z%{8eCRUWsj|@@W zG1vrSU>+VG6<9qgHL{FuX*C1V5RL<$>AyBU06Kl@`}d|{ zXGd$F+Jc1L-QBlg)v{mqQ8y#hL%Lc{eVI7%7=74lqn4pD&B^A8hiV8$M9l#`3 zhyu518F5PHIzo3oUh{T!TM1|tfg`3VUZA zY2o3Dn;i$X;CLanHi*Hn#CZ7m^LNv}&?_WIxQNmIcZfiu%Ebn17-Z+um(R!@D+ChT zlCB8dCot|mbvZvf1zz|oP8k*%zz#v{e$c*4r`F%i&x5-~h{U-|Y%>_9J`8~vybU)3 zQ^qo_0U%|w9hn#5BxnP^(Bh78@(IzYk)lGpBV_DA&4Q!&`u4+FuY)Itu6$f%no3}9 zLSzUHQU#DIH~=>B{(T&PiJzb9F%i}TcCL;*?q~x>;n3^ZMmS9fM~FzkO)P4^bB9Pm zN(#CiA-a&$88R_c#C~pena?H?d~l?mKz`+78_sxznXF8@tnRa=Z(u+q)Vf0UPuyT) zLg?fbbMr*t7VWzu{2I;-c84!Oj{ zCYL>`Ke!i!ZnnxC%=jak-tngV&)GKW(1XnZx8iUd6!Idjyo0=FxKL%WE=}vVb0nhz z=fRx6^uG$+@BvZ-iu^)(h7#LGC{R=s3Q_TLN?jBR|2GSu%L$`hE9B2f$HB?iL+^Ok zCMz&@?Iq}RBxoT&h7^wUj1MMoz3mAt=B)SIAY^OX9w4M0!mTT7YZq4<7c)c*0>U@- z^3Iv6P5BV*kY3sg%cnsxK|Vk1XZ=uJ`0*`JcAdan;m{br^m%_T5Ot;~vt1s6BDebJ z>(8y|n?MHkS1OH~Xr7DQf*5ufOxo>HyE8K6z6!N(_kLziJM&_IG%L&mkhfqzgOBJ# zXGtM&*cTi7Ib&d-orsVS4&os|1uUoTjQsp&A0klzq=SkFGqHv8L5Q9J^R4^*Z0p<+ zVxeD~y|n=h29us<3!HAsNaR-Q0IQgDA`+UfM~J_lzzxJ;0J z22GTy8}do|2~5IpMy=A)*Cc#%#jn-GkcqkiT9eG_7bpoi_wFr$p{50_V-p0Gb|9#S zz}S%!hX@Y3Q1qeN{J7xm-cXHaS>%x73%x&|$HvAqKwXXiEa3z;A0jR91kS=6biUu+fiu-k(R?z%B(6=bHF3MfV0Zl+ZkXWh@c=x3ZED7 z&u#jb!d>xEqA0_~vZImhnTAkAl_``TxRz+}J$XBK2Fbj{WTaCOr3HrT;dIwoJXCKc z9z%f}Uy#&rP^&NW{e)wE3B)eo0{ee^qYB~yk_X)wefw5RR~KKXW6yX72HW-P*Hs`J zgY386QDLx$9RTbi5i_6#hzOnWSQk}P;czs-+C9t@Umfskb2CAk0}UAh#8W`76atic zL16$ z0s{#|Ye7hH&6s?|#HtnSH5ruyDPLeC?nek_i!@1b6)8J&f`c~y7tr6%%EMPBYWW`p zU)x5K@8Il!=k!14A`#{BD36(hp_#n1b{!H}S#VTia8T1P<8Vsy0>%Nw&E~I=K}8g7 z>&VmnPo3fNu-lR-XOO^VB2x%11e*{6bugX2-fQ-i2^(uCX8{B(;2bv?oghc5GX#J6 z@}>P{+%jGMky-`-y9{EbLlhDj@r_y>KW$mcQmK3ovL~Eai~;o$Oc&Sz5HK=+Hw9@2 zP>D*xGWn+~z^;XncKmgI32IaYZiy%f4CdlJR#qBF%zrNG%zW@bJHbhuFcwA<6=G1q zDo3^$gNzRfyue43P0yaCg?Xt_{?c=`oc{1ZgXu}^l~@uUYm+MRqqMBIusRYE>C!H2 zCw}TotU7MO1d;-fKfJ@Nj2z~hT*e9hxWKG^XtIhq;N1E6>|v52P7pC1}EvT`x*G9)A>rl*nYA7rrPZ=TI55w`N* z0uT+(UN4AxX@IZoAyspch=C6UAhAhC*tYF;T+5|nXunu zkk#*(oVLbHaQJ_ecd-0Hx>pSgQvgiQyc@8felHLrE08=sJo){$FoZka-g2$R#_6$E zns@sS4pZn)(Gy6|Y1rBpO}%|0vJ13A3kU@W6`2JEVI!XE3oG}hrp2Z0fO25u4}VXt z^KPGC21?|^piWM;8E+>0PT(1S|0+89BshrXPE}s zU2C5nY&bg$0fiMwztd^}t1F&~tvvCJn$2xa-lS~9%kZ%Y$RRtc=Yz22xL=Tyrw;VD%b6a2{jv~p zM<%b9*Dh|%RXi%&(8v#@mv$*JhGzB2@VAw%Ba91%=NPYk*2?UYe zy7kiB!*5`}b4Pj}K3ZV1#R~uqB%Y&OEaB9LJrJ3epADmsP1uH59VzJ%$a|W$L6GrB zq;E)`zjqS-{m6#>-4)UUpAp0SZ>y`Uki|vPrl5J^Lg@q40CP0^cX`F-`*-hUf_@zT zBD&ClMw^2SG#VCG*62416frK0%~E&r7(`+DEr8IDs8A60MLyG_vN&~M=`&|qO+Ni- z12{a129DaR%{Lg2o4&km7vCa112B5(shW+8HaHI}{7vh;f1r?tfbB8e7 z&`-BsZ-DdytV9U!fmc89t9kz4G=(lhOcMn7Lc$h?A4tj{Z{&P*o=;Vwnh(b3P9wh> z>1UvaP}=cAd6*-K!1CvBSX%%m1%XaSJr9P#JIPnq?pN!yRo)8(%?z?z_*Of2`WAi2 z9I8LaIk68SdXkCvGNO11{eOUBH zD^IwBk%#`(J`1xp4^-|QgjYbe8L?l+W!D%WlvF&~wX(T?yb;!S zE)AJX9F)TG&qgFGpmegWhJ>dPgtHCT771b^>`X&p?yw@Hf$RTHq{5`&rhfsZOSA(G zRBK5?0~zRQh+ikvvT(t8{V#Ci5Qzu3pNbEvXt`#e+6JKuVfhGNdx;njz!MMQ0oqL) zH=Ad15*#2Gk^!17;w?XV#8HxM)Do!whq2&I!zLW%Q*C;d|HQ_L%Wr_vd?AIu=E2_9 z8#xC!0}&1N2t*HXHVDS;ArFB%P2|5Qm;Ozv*m}>DFOaV@YjoA1BN9qLox{8BmlT-C zpwmP>NTsHx&ORPBtO(&t162p{FMs{g0FLbE=U0GV8pT|G7Y57!>gGDw%fH_$XTW=1 z{JT+makRnWRRHgei@bb%a;qH&@6~6n!B~Xx0**@k?cc6q8+9P(K(eR>*ck+{L_p^- z?uH{AWZR}+)F)OToGbEQDh2GnlO^h|ZX|mO#(vhzTu4RiQd zhzdd`L0k$3ACHut{xaQR>x+2q-q&NH?>F{A!SvD!(*G9LcU1%s3FYr^W0<22NDc>K z$(72dctGjU*47M2Pr_0z0e=N73ygG{qx13ord>D2ImGg1VCY9IU-)I9W{|&CIu-!V z_AefA*PjjF6tm4k0utV(6W8H5;~fZ|L3^=4f)`?CEekOOEV;Tnpv`49>UfFxLlOK- zg}{IS?i)Xa!w8F5Y3>gJ!N^M@5N;;{f@K$R#0f+bnR4wr zgY?e&#EN?)FTLjt1io5Nk6e1VTJ{!hZS(Z+e*RqY1vth#N$l4A^`Dmrhy_*#`v5n; zd5t>YH{@eg%rt(iAD2vAFOXV;yBe*Yjobtf>p<2X4!C0vAFTpc1^%aS#-_#pFewQa z`fVYB-m4qp`2;Y*5Vz`=cVr*rvw}_*i6f(|o@>Gom(3?MyZXb_E$s|9Q=JV@_XUOa z8vS&=+or(Ap@xD0$9UjRk`=?V{R+w{@`WHO0sx23%3f6^?|QN ztWDnwCNTLrVSE0z$jsgKt?9J zaTpOwfxPp;R+>jt=2N;iZ-%~#YkI>+b*Wb2Tzbq|Q0>AvEx%p`9iya4Cu*#q37?SE zwU%UJliHPhxneR(X8ut{#bQm{X7A=~8zTSoxE`PX3=ax3b@_Xmm-j+PTWr09`mPF@ zag+oacU=`i^uD=G{Fg~ptw%24Unt|@sgAky{;Fv};As|7O-fQ7Rc4M(ZKhPVZROe7 z!f|J)n^^W6J=eP}!$)C(EDwR@Nzt`3Me2?RI9QPm3)9u#h^L}5~ zd7bBLU4->E<$BrO%~ViOU{UQv|KZ+8wYbJrxlS(mraNRVAnOhqymxj%fWr>vs?f8s zu_3>PsN7v#T!bP+nVC0j+CD)n9h-k_blp440-fc%O5=*oVuuPL`O)@;d=Hoe0sa|yn1DCdrMIkFo%egU~!8g{_s|>Nt=Q*X3 zYX^84Cjml2rUB#B`OYw)f&4_kT5Ps_>Re0%DA(%F2^Y7~Ut2d?ZCh`><7{v+A;?~X zuOdAZU{VZt5=1OVOnCUWN$Kg4%gg=%3$DwvyJ*-JTjDSJ@dZuo!7IDg*xK6uf<8;z z-d^C<`M<%9zdk>?b>~hSG#iQd?^07!rL*d~JqADcK`E@p17t(p>MY@Nzz z#d>=WW@crzjE(VzhlkTjjQr)3s-P@VEA2^1lLjmN8t5I~kEW}u7%wj`Q(&F$q`eEqzTrpW)cMtcyk?ggVj}{YS|+lDm1&f8{P^kE%NnN~Cjq0JKYyMiZDB;g zA|T~sZb^;%ENsunGbnM*Rh-5UJd3B3Q5bIx%>n*ciT4sFLb8<%ET($qU zIC6SV#*WOxp+;LW-^Eq|+k&hSyatjjpYGq{BPX^t5|0q0%Db5tPU}5fUGwvx&eslQ za&~l-6%UPC-q9&WCl$EO?B$~CSs1j_4Jmh=n&s-A&!VF1WX@FIy_@mp6gVQ( zxF8ii=vj$m*t^~u3!}^5Ou^;w)~9N@K5(_0f;fmsF0x#SS%J2eZZ*M-ClS}L zFVq!3k_+{<`yW68)dQkC;=tQIYHM?E@|5W&K` zOI>6EhtxXaL=hE@e=+XWphc{Rk_ms*s-X49~u}>jt6jVcHcT8%zYbBaQ+(ItgO;Lk54NrQ3(kwh!o*x zXAoeeg9C-e#Kh#q$jDUgnGXeT`?ZV{mh*sHl7I^!5m>_l{QPzXpL>ER69r`3%HEw2 z%XqTwN877ceCRug0wW4!Ht)K1>j1nx{rS72uh0DZUz2MGTcA|f^Y@o5$Ky-`gX_(u z2~o+7-Ut!kSH4uf8hw>TYQ3T81oi?qH@HzO;b$MVx35L!2T#xEI1a8X zzgS2VfJGsuEWak`!kiVvo|qPwf>gS5c5?!7ENSc3%KweA?=jBO$(fmbW^U0`>)2$A zP2a2Mo^)RC!^p@;O-pNBbxyMo=6s5_OkF7Yx@}A%& z;;$kmPn#t_Kfk2x>`O#w25AhczJK!>>^*-Yd6OGe;QnqHlS)v z;oKqE(X8-W_Y6z{@6VD3LUR5wx!NjYyB)0>DF@N++|j+%zon z>EpnQPGTsOriR&Evd;$xn;$)*hO2?J*h?=Q6ZQ&k04&eA>*NPsGM`hZLnnec)OC3O zBi<5+Z2{$L+d8Xrk~^J<@(yCFvaBCYj%0Vaw3Y6Rl~34}6x`FFdLonY4>=*H+n9lZ z2w_I+Q(fUj$3wqm%NBxSw1m-^K9`0y0^D9Dh}fu~HtwBOyo8S;&@d z)zoOB(vU^d6(^q9EVl6yG&d|eGWMUWYOt0l6DP|aQg%2$%qy+;;xIz7_Q4vpk`Wzo z^7dXTWxRJkMg=_}UJ-uTL)aKe@g?&Sh(`o8HWz3{mF9|bk8KT~akRNq(xqsy_c$^j z%NGUN8H`~20={Q)x2q6`GKvLkRqnUMWvBlRnm}HSrJJkul=7x(eA9cavhO z^4+Z=-L{?SYpAd9|M38G{aMts?|^MTVf{{heQpas9}P&mq_ngM5IRQ;Y*Lk{E*M1*|SJ2JY8va+)gpXaeXt(bQ*dde3q zXKwH}ORzD|&W++R+=76&?%urt{;bT*()8H;kDrw->tKZZH-?ZylRrs!3EH84-?!KD z&M|Df6oJ`}yZ|MoQ-jZntM6VbF+3c|&Bc|k3_1O6)Ar@~-5-dga19h&*o(&6Ur3`0 zj|UO9%Vpy0#GUH9YCK1GjXv1EoL2kU5z&>%LVrC}%w!kBeWV5B;aCTs0dFl!6Y{%42C)353!^0c#(U&7GMn^Y; zGbMl~mXW*U*|*)?)(!sjkbV)HlZ#8q!QV_aZ@E-eRF*n~5+;*$_zIXhFrp|ovy3s& z9_!292c+BD+PYM`6m&bfupaAZIUb)~=z_N-xw*16LOoxqIEmGU18raX-oW>x5d_>? zT3IpY&wa;sS#qqmw|DTq9`Zxb$~BjnTr;$`jwN9WsI!=SEsE%MpoCWSxkiJ znOAcF&QaB+y&nsFd7OyhU{^c$>ywVSxlXMQq!@0eG7}3rzVei}@8Ym5E59P2x$=V5 z;;z?bwbge*M0pfeTr48bh$@)7fu}+?)M)LyWa)UF=l(LCilU;T?zeT3@(R-e$m2-F z^4*riB&>78vW6DtDh{!S(COQIdBu~{6}bJRZ#@y5ffz+!D>wXGn3~T9&Wyb&k#@<&h2aHxQ(H0^l{ z#<3M2ap+s%ZJHmwaj~%o8oD8Mt9SNGKageM)@at7ySf+BqQ)65k4%8#hG9?E?L=B~`)!`;1^UBR!T^Uc%Ubn})iENF)aYEb)T6}#_W zR8@5~A*8`Q6T$!!My%8t(HmX1=YMnH1ORJ8q0OoMoEm2iv4=t%4QpE*T6Pk6un%f! z`BCgWbn*S{UW4|HmF!+#UW3$!aU!C1A?F>$t5s-l7su+^KsM)#tKbY*&O0QzabP_w z$)YtlaG+)S6At|gI5f}(ql3(ck{5qB))tWp<29_I`1_;pysN^Gxodfp6vRG9Xl-Si zY~^1^WwafPJv%()Q#YjE$8Me0`o{IO%tN`KTWD#*M!2RO5@$nbrhq5yQc|)Wq|=rCg7_dx{8uHCy$dIlloU7v2xyH4l2vH0Afq2b}y zp&^nq#juIP_vUd=&szkXKph2{i<~p?DJ@WaFTwk7DC&k50FQJ%dKpZ`^WJcuJ%vCM zo+k=*oN1d6;9T95@l$zy?0MA2^$1SKfI;+ngy6;gB{eIwecB$XQ8GcHJ`8p8GB+e@ z4sQ3x_OhsTT~A@Bq;>Yg|&{1WW`&O@+LuBW+8ca)Ay`tGL18gI6=3) zy*@oXz4h6%4M-Uag1EKn%!-$FW6*kN$WOC5+BuXbpD=ZfH7U5Fl=biM;F540EKb-p z{6kbiYD2}~ojVE`H!w4!v0bp%%y;!=^zitCGk!#$6LViT0%E zzAU)9XLCq{}Mm6o^6l=11V24zE z20eXgpE1)^0-b@11jqM}VLDm`H*FuphlEfB1qH<}L_l=S6X(Gia~C5RF9uQglT0lp zp$uy+Igm|wWr!6EAtDCyZ??%A=7WD@Y=j0iHFfjAfXVw~b~Pi8>8dz#x25=l|L5Fc zoiCgPdjum&0r3)Jp;%aOg&g5dy?1Z7vsqwZARd>YB7=xcBYT@<)x)t-~p>bDAD4?gDu$JrsW@ii8MnQNM&wr ze))i?h)4?n^QpQGF;0WAMk#&v?(PiuH+2mS80!llaX@3ah9WgBt>xLX#5Tkj0)>T}4*fSoV!Au?I+1E|O-Xyto;_q( zg{G7E`SIDKYL4|4UcE{U%tOu*{J929#5XD`1hBo(wBa`(Jk#~fk+SYC5yQJ;zV+6Z zV~|3GRqKA*;KJiIc2KzAs;$-X_g|)aoB@&vC;^dYLOg^iMNT*V4!=jW;cg|R{wysl zX!J4z{C|j|2SQb}vHQ?g3vY-y_@&y>Ik1~s$!uwP`RbQjD3WzSp9DF$h*pNdBh$c5I2sDJJU z|9txNsrvp(STCZ0@#U(XF@#$LC;}Pt>($*0&lWM$cc36ZMu0Q^e?lak8a?AX2>XV( zm?W0qh|*aWZP)Y_(2~V)8F5b9ehZBK{hrSN1L3c|Rb9;^JNY|TM%!3Frx%lea>&Ce zgj1i;__aPXhB1~*(%ZMwP<;RXz4_(KO}4>bIRFAk$;n-n@7Lx?Jrg_q+nOkVmX{wP z?S`Dz@DINxh9h8epKubQt!Tl2NU(2IEC54_;v9L_=rD^f-G@;eAt%;5qVWIbbsSsT z+GvS91rINl)Vkr}be9wZ%0uu?q2iO1mV}*-jBukTt8Hu-zGPu(X;iWh1SC&y-v~TQ zlOI0BPfprh*?n>y5muqOy9MJgP@Ihmv~9h;=aa7e*3mOHo?@w!v2wV%pP^;ek)_eXegAGix-S>=IUp5 za_KmX(zJd0#`W{(PXTrYX*szI&CTlJKZPhGSz<8=l5QCxyVtI5#jCJCae@WHNvsSY zkJ!_KBDl`N_R5tj{>q#wY2|(AZh{BLuug2*QG0%^0XR=yeP_y6pSfouXAzH1a*y$e z2pUQxyT!%ZN^28o(s=u@aL|&H)RUVxukqxfKh6Hb!-zjZ(#0dp(4_X$P_p#@SjKok z&DZ*U=2Ot*r=X=TUy6#>KKS*Skzx}40FjIWN%ZveY~u*gEuKb#N84q255#xq)pQbV z1x80YCZ?-LQ!v5G1##h08G9EO0Ick=AT?txZaM!;S^-)LV2H$szx(8e3;60di=bv; zLZe#Y+#|=mbgVjI##d>)G0}1uMineZ^nFvmf2%sh%Br@xad8FE)Fimt+e_R3i4K{f zEW$$pfeg`~owM`4$M;W+)$OGkMn4{nQ=d$wyUu(g0$|3;^u|qD*BR;Q`-8T2FG`m$ z%(_tlC5ADSOr#J{&@nQaNKJ?cbD{iMH=Rz~5JW85Xjj}%U&+eS%h^juUkrWmS+zX( zZ~)u=H;hD6`fcARM^94teKI*|JGedw=Gad_K3f6#lJ?fv18tfAa)_iAPA&%8W(5TW z)AEBaBjQG=9IGq_ym$Jv@tLE8#hoN+Wq_Yql=)%uw4`%_D)tx1`;8Hqmqsz zVb7mkO;ISp7aLdmg>p3qsIb5!i!Smot>?Pe&_IR;)Lsm3tq?Ko)y=+=@MOj~ zeHxO-eKX_4x(o&L;;W`juU@^9(-jpKj%_G?C+o<5>9J{YFRB#2q0mNq-*tGT(4Rt% z{2I#eO+bP4_Oz4k0?d`Obq?@2-&nG{4I!mMUa(q#r=$!kZRY}f6q{dreHu~W&O*SFSn*L zY06yxwA#JquFGAlL&Swr0y{!cEM*ogZ%#eAiHE1qs)!JXWT+-}DbV%w=~cP{mvvD^ zf$>HrKyZR4bYtP5PY3ob5UDyAmz|@dCUZzrVp5PPeWL1)q%5iM#$khiA_JsU(iCwL8LCcnww79tF{eDy)uU=D(owN|f zWu^j8p6jsKa+V5CxC+vJdJyZz$t6!O35CYwmmg41T)?kTQB~dAvnA;Y3s>H7Avh9E zO)7|v$aDvi_4YlD1G1)QQ5*K}LB+#Nq6h#cJzZRhcO9xU0mmVGX_=Tf|EMnV&ZbzD zQ_PJ-FfSk=fTR6+mwJY$lrDEFOeC$Xl+eB2!q`I=U9Zy@H-Y5ar6BGRzsZKpt+BiH>W@YL$7l1;6cpF z#_vLr1sV6$Peeq`=8PTc0Ni`6(A2#9$^i=-;JstLR|@v5AghC4NXXGz#@isaEzr!R z7@r6@5EU8(^4hO7;U|e=5xB?X^mI5n2>mPlcMpqi+a~)U178!Jj&h0SqxsuD$NQh( zmhO|6lan*i&sk*5)PL&F=OcJ~f9R*R+J%pVGM-4Ec-1I{)`_ja^W`08>^Y)o0c3?H>@ar`!m!VOUHSWGi_M!(vG9xxPAL6xc?TYBHy@YD`{IIv&{e(-$rpD} z{Sl^1S`eZxLZUAj(;-SXH645WI3nFTB{|uj@5D3H4F|bVda%Dp1p(VhG(I^0o_?%@ z7q)qOY3-%=2fDt;nWR-*=Q3aN9628W9a~Ggph(N$Pj<^qZsfpBM>ki zMp~GEHkbRRz-WT;Zv8sW?tFU(hr&B=7+iaOMV`;TejWDs5~oSgJ4oE(4B{B0G2l7_nxD2>^TgFk3`)a)^EG#xY<}R{2!?hp>7W=_lb*< z+Lqgu`7IP^9tIDf@AR1(BU+1RBp-9me3|?5#nQrpgjHJH@#K!@RSF{*FbQZ;`}@m} zbj@V>AWeu^K+)9%ojSFqZfF4vj;6VJMi><>TM>=+hA}i)M1l*P1qU|bp$nj9#`nal z4!M5)I^`!c>F#%OdQ&Q5ZYLZXW$D5vk?q8n zjYH5k9z6zzXy)W{I+Y9jnr}bqvJ8P?p$w(KGUMTv@sMfnaH-MhXa-n8%;6A45rwQs zdtz2+zy9y$7u-cVoOP2AT+YmV*A!b8H^z7AabY0~xMsLEqbxU@ngS$E1DbZqM zW+tX6OjsnL><>V$e|chPvWVgrD3lOT&XJK33{HHXTE*9DYn&E%z?MuuB9$0>1Ce2< z<>d1Kp|Iid?@32E<-f2EC`Q5{l|-KwjkEeJEKd|61Te;FobS9lnM1Z9ex^&9F{!WP zmraVt5y<8co=O9u0O7{vvPm0?Y*h#W=_%^`=Qcq2rRE_0VPPR$ouA9TL*=lWZHkh% zv#$YkKHKZnelHKaXgnnw78d537#kDQU*EoK<0FTv7K4jllOkklKztu+2%STmEPnhS zeVyB?vS6{|P}06@1Ar3+Ma81KcTbM}iDt`@Enb}Q5@Z<(KOZYNwUwUbtFB|g zK7x1&f`Fj+x1UeW&tF7&5ZbzREigMmm}7=Q=N^k)2`f;`(2&{QACcVZy7b0^Nrok5 zn3)>UY-Bu{i@%41ADLc&M&#&XS86taYB=x=pnr2;9}ApV8aN$rq(wp~$iHh>X1X<} zq=l4VP^ox5GSk8N7<&kpnW8(rAs@OGxFK>QiR}&b#t2a&U}CB2W^UwWWa!YVU_6$R zl`Ya*@2u$(s!o!6APy~`?P9VRUH84lLXw(>Mga5}d?s2zHvYvov$Ibw&kY2@Y>WYd z28kLNI=~49JQ4#vJ#E^}r4#;{)&;rz=XPSZOUcU@?={X*-XQCk`ecTShv)K~^ucd5 z26CWKCttso@mjbV)610>&XF}Ev2$k>K=z|F-CJcGg?~SVTLe&=__C&+w-TfzKxj$I zK9Cg$;v58Jia`iNeZCZ>M&*{e+w>0Qt5PRhx*uPKixmz{S5HqZ^z1MRptdq%Ygt%W z#4cD0?0wC0{yUWyl#a{Ll%V+|aUn?Xh=LO{CS4wF5)1%^&$cGNdx0bYWj`I>#elRj zD63eAk_d}z9e8juN&w+vU{C>~mD)T#KVQxtBMK@XS!X~}p$;Xz8xW8|591^2eVjov zIwIPY=o69i1^zS=i7tdLLZ^nBtB&MyktLXG<0NoppVa*5${;OJklq?-!Hv(z78nxg zEOLV+oKhZ19x+SsDM?lCkxHkDFKN&0=5xfR)Zf1!^*oxukGpp-n0dJuYCS=S9#oAu z#Rs_#(qQGO2I38ATsTo!dMN+>i{0+N!k8-nm! zDaKAKpuYv7kN~dq@_}KSJPpzK?Kyn8X3Ov=YrS9_JNYGlazcu%;$e z^k;M0S}*zT3G6Rp+fIMY^F+z7@yyK3W}qNyiqw!7rHCp>nMo0ZubKCCZfO(@(zufi z!dhxYudxtdSx`wa7m61q_{8-?U2b^vC}}>3_#khO?e!2x506W*+ioI3RG?8v0QwZ< zD|X-k2Oz=Z zAOaXxXI&X4@CBnhokF&1YvQR!{heA8Ux_dQACDRLEj*?nV=zhZ!-gg}hT91OB=fix z|H;)ayBr2R6DIMuZ{M0SJwVyUdELA{yB;+RKA+4#R|Nir2E!Oa_7xtn4^(o*(w#p$ zNK2?SDNX@RI$;U$(6}O?2#*qw7*gaEU0Lh|wVr^9n0)(|79-qHSizOeSS&>CvKLq- zQS9Oa5qUKD9Qi+pjiR97VCd`ZEzy{oZ)O6=ujAZ#8(k+Hr?pPItUArI^WnKYIKG|i zB&3HIp?d+&+)UhhIIfY2)jB?&^NP{z`JQxx&0l6ybwUSiZYonALYqz=0l~F_xeRJZ z;L22RH~`&DEp^Q`UCf||!C~M3YMak6zu!O43u)^i0_aa(Kqo2fF)W$Z{@a!*wu`@Y z9RTAxpJ`g+HwWfIayUrX0S5!k467weu9qj_V?F1b*jEi#4X?rPvLKU zEhgM-h1;BnN}=}7oo7soKW6jVK}ZvXE&QtZ3GIM9oBB7(xb!4cJp^~JSosFv6b1;X z(P>tnsyuuQWaM6)c33*lsZgWxVXy|0!vUIz!QeTE#9=#F5@578o%1g2=@#zyA4+eo zfw&&x6Pk*O3NkeVmj8sbL}s8I1lWi43uh{2cCuJgsf?58$Qz59Zj8X=V`JWbf3HkK zGSm)lI|j))h%~^`IwC}Q|MFnK;qv=?U+n>~O5$2blJMC0I0?5QQT1e7VA3GI zho+n_a6`0_;3dM3P>^hY5@$mMtT+{y19Lywp}PrARm)x71Ck?h`5Ao8*Y*}K*}nyabdxJ$DhTJ zkhcFMQiIt^P!Du>;LI=)gNs+9ibqh={D9&?)EClkpE&U``o0)i*QVP@l9@&v<%>JV zH<2$zpdr{}(9oI&N9nd~bF9tM+aTO|-a~&9YJBg&z&1D(w8fSXvQ`M$0L3j#*;dc| z0|LyXoJ3DoVq=2tAfl|+m(cr&*Z9O}6@GgqzVZb$Wtr4N;-a;&InX4k*E#z9If-;I zU86gZSvsG5hks4>*iF<_3U#nvB#Ryrws*HH1Yw}T2;&Id^>QERPMFiZ0g^W59Ba%B zgx-+<{+USrNyKLY?I?my9n+QRnyc5Zd$eZWTJ7Mrb&Lrv4PmVH57PZ zg+R_93GU2zLh|GgIY$~zIXVCCSZC;RDMBFs*bMOcI|>}JMnI`R6s{mh{>RZ{qfIR? zs=Vgv+M6sndi8woqEh+iET^M?T^Ur+QsYJxko{3slq^vX3r<%WXu9B-h0PhTxJkMM zw-VR(noZYNKF-cYk&rC7t1zWrdre7n5GE!mdnpmyA*(B@d{m5Og@uVJ;*zC$2}79ISY0R@WU|IlvjJ=n(uA@*6H*EF5{$ zc7EboTL4Sihy#w+m$+jz zCq5n?;~xe|$8-j&i=l=LJ3J3BA26@${SSs{*`zBA7*k~}U*C}KXBsVw1Y;y5xBliZ zJ6yj6vwHW=P~wncQfN|-%Rp|5g55=CP>=jFGQOt6H_A`x1vuk^&BI8hbHpeQAyvP` z4?rw&47q;^VC46f3HSg>1erz|h{S3CH4{3Pvcp=`#;?A9`m`4&5{}6Gr@x9LM+B+S z=sqfjq=$}Mp?tjU&I%{DpMcE_Q|Hf@@gREWfV+0e;jG^TWHkpPn`MW&DE;D%EH_7& zHTywq1{yhyn(x_3;mB@{0#;CHkUMU+|MjGia}>vA|A9;QrPI#Dc5xSpx+^uHJtB$# zltza0uSQ49tE;6g$@a0ety6PB(!CLMKxx`0TfeFHa~CPh8V5Gx+ZipS7o6oQY0RoV zB#2s(9f=@B5dQPQE+*WME^tzOYu0@$|PJc6zQhJORLU8s}^a9J*AP2qu|6W52X^cgHG+cju~ZYS#VC zoYMTTo4<2svQ3%Eq|tLmIs8%t5s(NL@dFS8b;5xL; zY)1yU@$RhJmXeYZi#qRuRxfi7QDal}O*5Mg@JbDaQfr%87FzGPwoah3vXbZPt7Ybr z2a_Zn11BxH7#M+TB;*$UQoV6G>;wb|OAFpgJcGnH+yoMa1@!&LkCuUfls}v2uHVLu zyZo&A4GmTWZ^{=v3-)Kd1jR$hXuyg@u!KZ)TzCmVqsa<0MbO)q8{!APn?+@850J9A^`v)dnth6 z70d^=O|ch`LCcq`e`Tda`?&M^q5u}-&6<7a=;`jBoSNDjbu&VP++ySNdo_S2U1GrL zw8|xOb#;o|px5;ObnJ*H1ba#jS<)KdnPHSy2a5;-lHBdKzsYIiZFFv^#Kap1WNk3r z8do`dEf|!O61#LUBR!p{1<+EYHd9etJDAf7AAwkCJ5))~1K=3L7AR=aD-n?8zGh_p z`mgQgCG)jry*!Z{S^rLN`AhDMBPctrFv+N+A#>@uTwL=)G3i1!UFj1pWNYA9g6f==l{MdF z(jol-W@Qoy4UGY*9>6cabK-5XDb$p)pcgip=)g56B<i1$cB2kZZB= zh;^@`tLMVZJf<}u*j77!p)Qj=nxT_}S@a$l^HTUA^y5VpQo>+NY@LML3B(-?5RYPF zgo;Tt=; zg_qE7B0YYfJheRjtn9e-cB&#Zj5JQMTJN0^QUD@@NboXrUOOe7zywYLUO|Q7E9hT% zN;~heVV~f7j?3#98L6^+4s)e$y>uUK@?L-YuW@KikmMx<)d7)r03;(Oa|qvvQXT;z z5mpKtM$cn2G4(3Fv?f z2o~~dFeWkd@^=-E3p)x=jJv9(IQAG2B2%ni0=m2nLA|-Emt>Fi+QCjnuCg(k6d1Xh zm6a9dQd%wGhw=}Q!28SF12md%KRJ}gdx%{>*%KuFs&&xTtwc=w2^YQ^;9K$&T~{`J zEL7`P)vop-3$uAEy+o6we4#Z2>|T~1{g5|xYqAFzQP82q7gEbg{v0}8 z2{wFbX(k+ zy$0nn;@_5*n!%g1^76)l5)fkzA|@q_3Bn>G{pxcli>-Z$2m~D)J9|N(2K@l&h=5lw z{v5R^V>8pwnI}374YM{V>`2BkfY2ACqk;kgdrz>8Xq{G1wqHe@J-Pe`jO@~$dxkBJO*7;2-K%-v6`CX0$+4igWEO7OD}>0 zCDL8g529HF(p=I?NqqL`sFC6*_C#Jv%5XM$0W#zvUy&J&t!AkLE!_!Og(()>xzzvJgtZi)MkACkQ%LBCpkkn>* zVPOIJ+y*CqHw1~!GhjdC`4Wj~yq)W5FUZKBJ~ad#{Ths)wx6GDk5@G7U3>-SdQ9BU zA~MU)77=W|nj9EIzRu~^n|XOl?G%+<@UzsEp&G;2>4AkTJ=J8HDv07E`OPFiobZj{ zXvydbz!Z6e8tvOno3?bxrcjt(%uP9ZPjo}T8?|k0LA`l<5$)KL1`%1t?K`&Qg1AmML+qS#O$By4v z0g`gCnDWqnabSj~rgE<*P&Of0Y{uYQEKq}G3$BJK>zccrsr=-g+>d|G)BHPOonBQU zzYk7+wcnknzl%RbkR0OOdcW(o9W03O@|D(dk zB`CFFEz`3ap>gtVC326LcoFfH7ntZX&?`51N;QeL62Ej=B#^7oX;(R+b$@q<$P zD@Qf5&Q32b8dNkR-P~uYl}6k|hutf)m%n_Y+h;y-HvRcRY5F9E3pdk(+eV6O#WB&& zD#-L}S7RZSmkC8#f)|9Pz)+Vt3l2nFX$7kGn70}C@q&X|XB&uzhum!ec_9#l{_bOf zVS@R8n>+lQ=@=M{pYjhaThCKJ$j;8jJ6(gNhjn~_=l2oY;7(GP($ef91b`4zKDwi} z1Sdc<9K#Vr&WTMyte*swhrnzK1<$lfbocH}m=?uHN)2c$P$Ph%mT~5Sh@zyV1hawk zSLRUld_!Mn_j>oR{_aL}W&exY;Z-}!1q2M|q9)cUu47QodMca^%-fu`ZfhuRyDdUX zi>nXiaI?ANm*hOJl>b+~#f1f`ygu9^)=XD3 z-WgdEtoPPoU!$}KTJX1TwP*TD7;wN;Az+GJbcA9H5otjYKT+laeL>LB1;X#RxU^zq z{g$*wOv*KFmJ6Bzbba{eecAf$&j}fqojq_y!KyQ$wz-2EdJ7Z7=(T%&&H2<{9} z%R6Lw8CVqveRLlwYCFrAfBpJ(%l;uPQSbtMB98hcI5Eh8N%VI(@!UkSQd8wz?3^Iq zp!-jtQYd0B`edlBEz%{WfmT}-*U%6hGMN=fsxWa)le|yJCvG-<<009`@GNGW;}aCG zjIDAJjrk_I?cx0Ot(6~M#XEO&5BkZQZd5eUH;Y5>PA#g5EMJp~kq=ty#;6)-v~4y^ zWp*jzq(SFS=%oTfI=Dt)=KAXu7O9+g6v3I?fYIRmP!V}65jQ|t@Jo4m)TlzB7(dCOg#~=fpDamRBrG>_jI-z~jitMwAi9>l) z1nq=1hnNPz75_`pfX3QTDjm<^aJ{98ysX|iMW}5pm#sN;1DtF7Dti;_(K-qlstezCO-Zy+C7W=F&Y$BR2(0?|HgEU(X>Er@*7K+ni095%DA!< z`~Is6bqE}EplR~TKfJpHNk34Kl9 zWk?$c!h)s*V&QyhK3m&~_3fg4@~3)HPjMTtmg0r!^{Q)Y^X#3VLrlyXYe&=}ji$@n zT^&KE3(K`0G20LRIzzr(7k^D4qFPZehoa?VxVeQ=77N!ItYy;Bej0F6FL2hW9r$k? zj!WI*XY221KF~?@Ndr8MvzT8&;qdz#LMh2N-F063$){ z^?cRH4bWuI?`1Z;k9V;JD6-7SpmD9Xw_bgQbwD&M1IZFK8T&7AX+JS0IVDJZ05pWd znOwz2p`E%v?dJ`2^QI*qh~zN$+^QRBUZd^L5$zG-&T4-Tl$|*1txOSfXUYW8y}pf< zue&IjQSAY3LVe3qFk61S-Zt&K;`iNT)k0`kAO3m$d|ztuxT(!33oWWgro>xs=~nd8U`1PGB_iNh3Rnk;mw(Q zKO=~dq!yDrM$+>kwW@W~iAJ(+=C3B@=2rHXZkUr6&#vf9FL|ucG0M8XL1k5r6dMy4j zGTL@m87ZaCtz}YAvL>$%RwOu=;pxgp4uWs}m387PD=P_4-0WobDzFl9L|~w{g~f}y zC;2HA)8YWI;7tWAwqA&_0Z1Ja@Oxy8JtW?liE}^Ws;yBv?JwsfdCKtftG~ZpHmU{p z=XIz0qrhjHD}GD@-iJpcK6A53i*EME9@KMe{@q>=eh1DoXTK*nCMP|06vie*O?zJ(n0`@w9lQhN5oY z3fu>Zymx0EML9V;6f6unC^NNh$`*842e_ROJ3Gkz2D8B$3h{(%oj#^j)_OA$)ZVzO zgX*fl1e?N<+X6Lcr%_zKeilAmDV&(%A$VgfE7s>Stu~ew0x=RK@};w^**Lg5HCluj zJ_V^X?XpYUkO)N+f#Eznrl9J;P}2|s`jyD%5$FXVju>mJGROMp*JRU7xA7FL+^?EKWK?sBzRSh z`25JIipyc3tpPR2GvV=1vf~TvN=R6k8XyhBH_NMU^tIiV8|O{V!fiF+q&2Cgp`Masj&1(FS)qe5zk6Or7=tQ7 z6L4;$^8(qzjw)oeMQ7Z=0ka}*sT4~|Yur^{8D2jL@k>!fMO?2fJ{w{Nj666`X@)qN z64w`Qp+|?bbw+vct4L?CP_W+GwNcVf2AzDSed~etWeq;dfZLhe_mz{w{QqeO;7o(0 zh>0Qy(I#jX;e{>^WY_vn1`83LG5=oa{gpuc@Vvi+1gH3Cw`8LTO00saney!zQkmZJfqqCD9awCcm z>>bQYfL5lV)ST{W4*g5p_UV2fRwwEoA*m^;s5sirckC|R9;%av=FUGHYwIHPl7-;a z$<#vh<>1tV)oW^Mn60d4zWjh5p2%~5{r-(DuUBM)MfLK9rTi5}{_{Vg5>QbPXB)XbiWv3XhW{c*%gx!Ngr)KO z>r3QDL7=HkBdrYkx}0CyhB^hi=Rc-g!w zJ^X^G)L;iK_cPITT(E1AOEv=nZnw>v=u`@5rDEuX1+w+|^OG9UV%YkooXJnWyc``} z!iR+Q>8bDa9YV}n9K~Ra|Imqw1bvKNUAlYgl_pxUOP;Cq}?f@MMKUx zIfQUlDes(L&CD94H8E0e#9t2!VfLVmxKtc)VY}$qs)~vOq38MrPx0P715}(({)4kT|)D zZTfyBWDehe?)KNown3K-C7{KurLHLOTqw}R_2@Eo*bqkON=}X$pXRuMV9g_FyXZJM zGqz>fNagTgBSIUY#a)Rrl;Ki5cqSaImLzbrju3murYs;!KgCY=f{0DE<} zEPq;AN-6{o87(<-dvzQccjBSLx+4fs2mU_Dxx-P~f!UGz_4%`}{-b^x98jlIAdYLnW?@WQit}ktsX49oMq~g>5+VZ=qmxj;#E_Gkm%bJOEG^S>xlPr zL1U_P&op!`iUK6L2^25zRPXu0GQEixJx;OHA!;(($9bh{zv@9{IOw{vV(4J1(Ec97 zA++HH?6j|eSR(K(tZ25*Bro9fhZvQ3xS^m#X@vvl z)P$~5=EEt2uDaMeYAN$!SH;)(1gma&b83Ky%$mW2k!XI5zz0toQkVGHU13nwmPyb~ z-PLC7V8p>S)FZsX-oM`3ODc_16J)bJ*zinwkBz`oh%pXl8M*ZdU}QDz>O-GB#c|pQZH)CpHB#ip zt8dQ!4xdm;8Qj=#wMTFD?4B)uq#iE`ALtFp{aOEUp#f26;26idT3)?zVOCL;s1J1J zS9`&1gY8c?87N4gL=q!J)VP z*dJFg%mG@d(Z)A}h!3bQpbr+``HvBp}e@xK1TEUy)g*mW?G&@$v~07mZtz z#L~L*QXe;+>QZ#-<2tTz1Xn~5Ao+=ay>0av0sN0o+P@6RyFxW1dZj^Ukb?4LzE_7M_9irbzYy2v2k+W;^l_$ zLb0~9B=Ajz?_>IGk$;qgjWTWngFeFPvf&HwV<)OC$ZNvaKH6@>%wDNhiR@k4@Pg;F z$@m}OMxp-0ID3QsrWbCdgIB#?InrEA244=Munf#x#$An7KdcXtgm6-WaZd-Pa{#}{cF){>a!1If1Lrhz1SDbu z?=?-t$wH&3Zfa_J_hf#^>;@^Ziy8;Kl;2qWpBCT%GbGw5B0$mB<4yoXR>E$=kE_}- z5ZtKyzQP&aLQ!wMu4ZIxw$gUh;m}9n1EOqbeln96>=Xt1McSZ|LS}JD-)zmD^%r~f zO|K7OF1a^Xe|6mJSUkxnw75}rHp=bIutn2)Y6I8kYF{oD)2 zSwmA3&ZWO8dHuU{@tFW9@8xG*E<5*e)LL`4!cC3`|9OkozZr(O1`ZuM<~(vs@u^Z4 z@Halr)2jx?6^Avi4Ip>3pjUvEja>Vfws7)xef>zq8|4@G zTbko0gpOr5g`C@q=xh@&v?|VlT95~! z`tZH{RJS^Yd;-9{dAIL9%AMp5{h3M>wIt5z>qS}?9 zSJhjeikQb~6ZHWgGueBcp*!mTOQf{Nl|IClOHUsPqaMH#ayPXj60(DEH^kXLZKEly z_KRx~=YX||pX>I+?r6B}w-VSsFk~R83dQ!k87j_O!TovDb?MA=EkRbo@Pb*`94+>v zLF0mHP4%5kZDr17fMPKJItC{Hp7X}Ug;xMc7icP8)}2--{^vG!|uyRgi-)yp{ zMzJw&DB?$)mkQqr^#`(*_q;0(@3s>$H@^$#k&38&2~bJWhl2P61|)TQ*)`$UnLm#b zIkcl5w$$!e;lS;vUf+W`1Fn5Wxcvv0 zE|9C`xR|^?NPCV})maVFQ&ZmD8a1%Faycg$JZ4Rbfv)bmBs&xK2oxk@+Q5r}Mn$bD zrLZ7Q40fDB=a_yc8R>gVM{@R8(?6Fr4po*n#*U{emyX z#nJ3DB8iuL=YRQ(o&Wor+^N)Jr%up50YS=!-j~L7E8V8u~Wp7#u+;r>P zR@Ap zDR2ygGHqVpN{3gupW16Xg?x&?yZx@0m3bKZbewa`f7*!=m+ z(ry#`K54(Z{;9?%PIS{c9Ibv(m(FE#Pj*DxT*Q1ec%l4_{?D~gPK|8muSc2=7C>01 zlLiRZ3mOF(N0UC1GkwlqX2z74vcO_x)6tWTLtm3fk zUCgP@KMpck1XsU41jo#xtWD;4nzdU2HM}si=!A@lv<0BuV&69f;IIuF@)Nl(1sRYH z&mD`;(g?;jh3rV{-yw;Xn`E;haJ`prPkYa0k9V?HkS+nuCe!G6ZI4U1c2TH)F)sDo zhk;cn`S<&0SI5t}rYu8s_F&{dzpOn>I>-WWN}isxsoT2SdM)E>Y%Rn-Ak&cMxaF31 zYVU0F@)|hg^>hq5K>76 z8fvu_%Vkk5t~1|H&QZq#CTfe=S8Pn6OSY{C7yG~XKerx$6B{?NplqV&yZP$z==;Dn zm8=iXuI{V8dwgd3#l?ZS3+nt!NgUc!AYEg2Gb_z`$TXlFkmm-FS{szy&<%D&c6^aDDr^zK`9Td5$Ul@N<>`-onUjl zx=_o)YTrmxNe?3S>HF6QPnsRPEH_uu*FSDhh~0)$XwY3A_IgXjs}mzpa$;i9KI8Qx z5wE7afo{ihADO%Kl4Vmt-xzjRA~F;)ig=wg0o@Z;=#^P+PN zg*RuDE2l+3opUMq3NM^oRE^j{f9>j3DII0p)I&lT$-S5WKlTbHQPkOMe1_)20XEU2 zTcSRTL`wx0D$;X-*CYB_WJrG4kvAc4pZ!W?-d|aaodL@QpEHm5SKwyn{GNs=mM!a0 zBXGu$j7L?~@tr%g{9pLtwi$@35svxt<~ZLzBSgY?pV2v4_v~J0%i^;k_uJ%dMl3fMr+-?`d$th6pnl8;8Ro{ZMq1O2QIp*$}7X1)*rh= zH_evZy}a^;WBIfy@G&eaEx{z6?X9lX;TIr*ML+e>`rX?3b$JKlkUP?Fj)7&BuVPMA+xmP94%G&k)8{W zog@>*a?57UF1m|W)jYiPAe9q68CmTJa_37}yDn<_&L){G1Fy>67?|*^iIg4l^0!mx zZtlcGe`}EZVO>e~NtK~uy}Wt|sS(ooB{gp;Zcd42B{%P9a?UtyAb6+D`aqBiwOG!#PJxa{gyLxP; z&Uy#PEei?irhV52q-XX$H;OodJ;|N42zw@!ghI)lyI%UnHS%C1peMC7iS#>u7MGIe zi*;=e`Eht*aL&K9v{W7EJj^H)rjoALGSEybrY!a@zp+j}{?1=n)BuB*5U#K}c#RGI zX|aH@nl-lNYkebjd@B5N<=|GlUW(?ME-Ppm zfS2HnK0PsoYiwh6(T7R@ztYY;tjF{X`>C`^r9ulKNf^pbNtQ~Hy$KC1vPXr4BugbK zOr;4)MB-;(LsFs|gODL1Dr=Oor4aAu;yvbg|9|J0KW3QG_xn8eeJ$s8Ug!C8UK_1~ zZfUk0TwuO&`hCk{CpAW-T2K-8u1TSbAGt31+TA0a%H{mdp8YlNzGiLq!lpcDUbRVd z69eso#DhYeXX*ragc2^Z0`&`;F>$@WW$zEC5HoS7sKj%Gbu6P<#K21JOBRiG7bQXt4a`I^T*5Yf6|D` zjy{|Zq-kc9I&HKY7JfX^^2e;+8&35M!f1*r02wch)9$5D*DO0T{bY&YBScWrq8H~u zscV~$rGplXZr!3q`MVc-+Zn1dh*p%h=6UMl9rJfkE7njD!1s{2vtvh9>)!KE1u#bB znk?^=wYS@z`b&cn_g)T%jJIv^1RkP{xn*_XI562E_tQ~*pRZg+kE!hu3J4IKWug(G zh%p2`8bs#nc}W+Ie?Q>ra;DuhzfVnLT@Sd@Xyy`z$PFr4-n1yg58mx{FYr{B5m#o? z>SJ%tZLvG|UZMZUe*;z8Z7v8SJ_l7`mv?=1{*cc3+RCt$Ie1VM-OmB0$^xO<~d^Rf`%H;a7aaqyX zJ69xg(b$k)h<&B6d)3z;9Ugw%*t@E*Hfg6bKs<}puRi6S?iRau>9EK8&R=eM9&k0K zrl)W|RJAwliJiMym#FDI-Xo(@^WOA%aL0J0ML6ef(L?jr>Pw}jW4DoSv26^`voy7#H^&CPQ&IHLRlsDz=vJ3Y}x0`(#Pgi}KfpjXOrAZY`VrVBO}8ibGRI z6%{(z4ouu@5!K~+=6S6HcjpbNyYI9A@L_p>!8`5`H!xUl^*zO^Xy(M=#8=kwPBnW` z3gr2!T)7#SYLSslcj{+zbQu}3T@z5)ZOV{@sNwR^#@O=6 zO3qqumCvW%WpwU}!RgL(f4>Q|o^>zKDzf6RTQ|Lxopd*B-5umv=Jqmb)KtY1O>#Sr$9gAWp*bJla2Gxkj;7IUiDn zepD7sxw2Suak^w(I;d*0zhy#ME{{5; zxj0|FN8-ahZwJu*Q6jTYO^KYnb-^Bn^J^FmqX!f|%sb=g#+{$`+>zZG!`K-IBh5=k zk4lLT{_y$UzzZPfx4N%Bm(hPp;5>T-QYFZ(G^bjiXe?`GUIiEW=&HtML{fXyd#tUk zB}9lhp6I&x+Jz0@2#kayAX_gHu3hustE}$nlb+sAR14&w7cn?;mgEYC3VlI7ddFEfK8NJsW3Si=D%Slq33uyOIWQT^V&&HU$i z;HQABlI5olek#GpV%xuJtA^6R<9+}Qo}Q2jX)O=~5@+vl)-6N6x&SacfZYn&fvtzr zInK@P#mO%1zvuICjWCA${h*sS656D*T#$^Oevbx-9XP7$hmv|%X*{rt?~zetdbK=& z!K9>!^2?E71y37XDvx!h6aB?39b%zh=eyLOT=GxEsoQ-PjP8Fwg-&=g%#(5Y&-Dri z1%A+LG}-QAZazBg!?`0=Q1F>Ojz;1eb#RuR^_vqsCRVsuI#CEfoJzP_#8DAOaNLMn zPQv5ua&W~$QEXxT9=)o5uGw|ChXF%-1_+|`gdbijxGd<~iK493`dudO8)6#k#rGIo zK6!Zb47ho+?;dC^%Kfau_`UoV(mb=YaB7H3#f2MO@z(Xg_Tdo`J=bX}RU18h9bR$G zrpuS9llI)kiaD&y6xF6p>BtHfgx>T7y*L|Co;x--99x3bB4`GwC=XOQWcrL(C@_ej z*9Is%F57xVs68F`l#O%tOB$R@A~94+7|FIdfAi?1TVY}7EV?vP9_CeU-%nelp%r;~ z^1+hopcgJhlN?T*J7-8xkaA8VLMhbzPJ>JL0R!&eSW*ygI`>y|%msmZz)jk0o6)}~ zkk0{EWUE?E5TN&Ob&QUtE7IQ{xlu*_1I zAu%U1?IP%GZ=h~RX(YrLwrF7U37+`xfr;!s$UqnKiu{M8lmjjs{Lv%va%JE!3;pxc zCRa{qJ#c_|FPoE=7)gQNQIa(MWgcV;H zl{92UMtmoe{+)N4dUZ)Nuezq?0eQH2lTAUhz&m3G=EIyi9#B3Eutk=0ff}!Ms~#w; zC&Pv*daP<(qTi~OuD97Eqo`E;*O@3qLF1AU49y9Cxw$wEy-Db$Ui#0fPp|Kq82T(V zS(o8{*w4oK%m%a4(Z*alZ?sq@3N z%O{#qg5dRwi4>GLx}n^E+D7;;J4P(IF>CS3eQ*3ek1$@P-EJ`8_LHN959#~`MX@rV zR0z0s!fNH7p()ixH60oU&bXt6NqE0saxfw$bae(AT^D3zC{8`~caMhV{d3cIscewr z=9PzL!qq;iExgS>Hj7Gy9X)Qs1Vwg+$pY7R4Af(TZEH`Tbp|JgLVduo6 z)oZf3*!NORSL55KFW*f{zI((w7cxfW{==L-e7<#bb=QjJJz>t{4!z&5hV(@IQ#Ul;QOu-&e0! z`PnJQIKg4w=Q`j|QxIbYR2vBdo4>4vM(uHP{a%lwBWRps96ORZ;CeUC3&{u20RN#> zpjgEf!(_R~p4)$~pFvN^=yR*e{!4wzz&;CLa0o=f?Sz#CevOz!8J)jawjV=jKcz95 zu9G>!S=%!#c`+Fr^yAwH&bx+>p_*i1rK#^v1Uw6vKyis921w%rZJ<$c|bB2X*~LcUa{ zFGDK;y|qCp7dO1om@u-F<^b9>IpJ(9)x9l^2I~@`Ke==){g)orxiwl78jtLK=UNTja&eMXnc$X**D_`&ldc zGpGF8=zqM0X-xRgyvo3eD;xA;oCtWbVap+w)^^7*vdAqk{>;+B`_Id7%)_}#sMtejJB-ncQ-<%W&VX?Md|#2OZkI^p%f>TJn; zM?MNrX8e$v?)0O$iJeSRE_+e_An|`H$wj)x#?4q|hu=3Kd5rKJ^V|KXAAuL9KBD&T z4({uc+kCy%2?feGR4GJW0>WJw_f(wHNY!HDhjG+dq!XvCs;zeSOG_H_YLV~k*i(~# z^Sk=t`@Pjg47

`E4@O6^jR61t?kD;_8~NE$f;-Xtw2Y`RanF$B+1KF-f~Urw>)X zUz6(@y1lGj>H$wFL}nX3#K%_nEMla?N>dJco0C6$ZNIFQY0Ph!*NH-nwBfK~!f6l0 z=~yJY_BzK;Uee^e;gRQVKkosA6~z9yNH^*;zTD{nOkBYaK(DptwoBy=MjSD|;~6G^ zu^GmGw0|_wv)De;EHik`iI(R-j*aHR&7NLBkPTgQ#g%j3E&xSB}FLgSX+h1dDh-}+9<_wd;}m#bK2eT=&qQlqvqQmx~)0js_b zVu<=@Y;1Ym*;2m(2GWMHni?9p=$nmqbq(L3*ZIWx>%bT^FY8!?fZ)VZ^7d_G7kAJ2 z@;{DW1QT)QoI*FGJXHGfHNZLl~u3cMl z^c1X`&w%m;^+hz9Mg2@<5qUaw(Z!?B_O&-ysRNEK&;=TTGsd82?!!@?G)?&wZ2&Y`_t#)!LwNm|3L3^T z<=s*I&3vv;6@@XY{-B*tT&oDfch2r9euD#bj=k;i@ietkwaQuBuCk@jCjTy&zPw@RMg^xQBPoec+Ff> z(cYj@cmP-{EAp{q|8ZS&WPb@AwoWaeC z>ArQGMc~7xCz}@U(>v{cW6R-84Xw8^zSG0US$wqV$@h^aicel@w4N6w2qvsLu{ek~ zAFar^3IUeE4bSw%;LW3day_A9ldO4A6G6k_ESs`Tu4=OR<=rI>#(Y$LqJv1U{fUGp z^htR<>z`q1)UUm%b5ghBd-r-REpIG!*ydvXGpv;cRy2>@yK+e7u4(<$mW(2rP__dZ5FJ|HGO-&U|WB=}KJl}8KB`@)JEVka5#X|Js ze`9hI&w;H0*#82*quDy9(f{@#<;NAsmOtfhU@Y}{^YqA6LLO@+BJ*QDc4t-f^ZMp| zECaeWRc#achCBqfHlgqAXy#x#{-~wKk+$2y3{Q;me1vtcwe_~RkMk51+Uhym4|TOx zaW!K~K$$fqLAA0A6_;S%pqTt*bO}TSokQdw)E=K4sONZ%0>!#i{*gAJoJKcKN?F+* z1sU-0m|HWxYXXZ^6vD<6%%3PVZ;{_2#^Y!KA4ZE}i|uYxNCxQ5iPeCz;-&6OnMgFD zBcOo&p+xCC-nbHlS6UKmTu1(<(D#MY1q^S3-*Oh}U!mqx4}ZI7(1HrcuU5ew-Q zML>^i8BQ4UAt4xWQ8N^oKD(DTKHbAw=fuSdouU4gIV$zQJoaS z(rlwyOVg-V_={C6MkVK;HwXL(IJvKxmR8W>QtyXfhewC{`gUVXwRL1Z?W>?ca4X8i z7lz9D!iA!XC+C;+3V}!WbLBK4;W=lrZDTGv~4V-@_SRyoEPtf5!%dHzp= zhextM1<^Vr2n<-bgY0T4z9;CW`ydBJ>3As9B51_ySeBkh4ug9O+J5Mevcq`kqQ;`q z(e(?(vq8`4_D5H(3XE!6ZEK{Xle2yX?6Tseo~IT}n=xbWA6sj&@m*7Z0}}kG0s!ui zd;3?XTF6QrjMf6Qr_mdIS>36jQ)uTH$XjgtBX)5a#hR@Js2%1^eWsqZ2U4qW1_=D3 zx*+PYqPoCdGUY3VRw{iXk7k4OJDNdB6+tyhA|YG->P|eeb5~VF*r(=W&SHl5PIe=UM8#Fo_iU9mer0y%Zs89ei)6tq$~q%3dxV}sCnN=CHn2fNisCzH&mDQ z4ApGmnA?4~#s3~!f>#0-i4rTyIh#yuqaONaCl8FT8g2m1PUdMG+^vh)w(Q!?zUc1#sb;!M<~n+vcHh=4^Por_ zr&vt6UHL(}K8*;EC9ifLuB2cfV2yYb&FljeZe}v2g`)(62zloaQePe^vY(+}A3ixz z(R)N~cV5mK;~V|Cn3n-l6dny|X2=+c6X>|zUxjx<)VZ?$8FyDus#%>YyT3GeU|{o; zxpH(wW@4e~!1?#BW_7;WFE-FRSpZE|>`C{S2;_J5-nBA-F)!eqPV3eM>t~Ez`kWZb z{RQat+t7|4MV2Ed*+Gny2B+BlX&F&gP@iUnd#M-Ar_eH?J4aG8q*9j?*AIzNDO1V+j9Un%t6ng582%HY*@s;8X(cXuB1w__vC=C&KBAdxp~ar4qH zhkkZA>v(A|LNYQxPdIoNOjnVmF?wS)EiD>U*?lUfi(gzveJQTMVZxr@wE5r133HaPyD-hTueZ{j+{9tLsLXbZlL?Mx=(}eB7r{i~uqI*u?YBJ$Q5?xI z_ZNFDt7zNZ5C7G|d93l`J2UgZ%~GOrUNKXY9E5@;21YBRenzJ`OomGOzIU?{& z1P`|D99!n8DU~Ba>P7~z`*Ve@QBsSfAra`rLFwBuip$(Kb+PLW8c@Ebs`)` zMNJQiTM1NM{L06arXBJa0|dS6)B~}v%zJ1pACIO zvy`7isy$U0zSiNZD!jU`3BMquh+(^Bn^XyaTr4pmPF{bq0O3Grqf9K(#-H-}dr*%S zXb#u8%S4&M4Z9{&8jNh$+@5nq;0Ya_)xz7-p9YT&BNNE3;>96?`O?f&reA1yktEO% zD6HN$I5lCK>aD76z`IyDE^&q!C-Z;Vtzfw<4A@8{MVu#i^$rYfniUVsI>WkGrjcX% zVoSEyc?;!3v14r-UlMRLgi(Y?i zAAhkTU;u_Pu#T%+h25n;e$x1M>3~Jg)WoY6eee?(=ezJz+VNA=)LVV}O<+*~+joc{ zRG@4z3@Hm@E)qm*4SUZLeS4H4J|0-K2f71=iQYSXU0p@GD5@s&?zvAOUH}cR{bQ?@ zf+RiRPONXyQFI_#{R&>5W*fHmYyIHwlcK$Q0v7^6G$r0Vtxl_N%8{W!&ZWz+V*DXS zcYtJg?nVx2p97pP>`vM95#bY~jgLLvcURZaa-^TZ=8173QCMu%i0LB9$O*Ys8CV44qNcz#V)08ZIHCH*lJxCw`H4c&(9**6#}O(O zGkAJ6D9t7&Z{7T6u2_D&H`ooeD_ic=BiFypq&|`~y<_l7qs*Y{Vcy=m$7c1@onF@N z&$b-)@%lvmbu{r$p&;1ntHx5?3rsB@f^vQ8YgzxD;l)@$W)~=ciecxa`TbU`IH2Gc z;s&O}7D5+tA;W>cD*vY89>(LMe~CbmmQAJHIejYlqBzT*9b0XN7AC)30G*x%|f%d zz;-`Y|GMxc8}C$#X9h^*C9fRNZ$S(oG7X&@H2&aSxZ6;Ls}@#_m_+x%KxV&d*ExNR z+&1h*G#4a_JeX9AZs^v(6*JO zM~uzevr5!4ADX31TFsAve5@YcgBnRJqdLZM3M3t|Rb)PTdw5w{S*YzQHmitEKte#Q zs;3T(i8d=etJkK@^(r&f31)MDJfzt?AE6G?i@em29O1V2^}Xkn7u7O!w%d?jK|(pV zyI@NP3;7ZXB8wq=OXg#C-0v0}*fRRiPi61suixIN3_M?LrV3PQMly0qPI#_^4LS`AT5am52lo&|G}DVMEyZS()mn5aWjL zpxl0%nEkC2@RDQ`2#olpi+Bfb#(^-zTekvwm4N}N-p|x|#cGPK+GQ6)6Q|oY?;aO8 zIe_JtlkrstoUD__h^8||rX!La43CNQ3Je)V`$X1v?j7~q%vMxx&B%1+A8XZ~>Np-P zekz*L)Rh}~vSql=bj-a!f@CPBz%+HzsKDmFLYZ%c(ykzmdzccw=Pv1NIu$vEgPVh_Bug`VVverF1)7)ERnZCZw zym{kd)UE!UfQ8Jzr)*(=iN@=fIimVjCoq*Y|pTD`?W|BJfx;VDyhO48Vdxg3328%k~s8k?z z*Xvt*KJ9F`f+?7|4zR=*>^<|lcINAW;X~zP3l=XX$NrXiHMFXi$e*>y{g;W<? zDRrO~UQg<;O_y+%x@@xNguM>EScagCBJ44nlTV1^ijI+y#-7`1Ylh_1ZzKAC`*d_w zo;2TrNxiGcJJidlwk7|WIJ?URC*AEbUO*ECX!y(MSA;l9d9q@8!gqBbgTK)oIyOB| zBLr~PC9cV(#e7SE#1QNVBu@%ly(%!XeS59a9MLb%A!65@! zPzhj8=JD}`gIqvdyWd{k>D$vPaN1nBAOjIHo&DyM?2o!meY-{tQezp}@zIRXU(WLB$aKHPcn6 zHD<(+Wgf?e1E67{N7{rP!COXldfM<6?C6}~^E>0GFq3&adC}&9h-$#cuO;1gL=c5e zX4%KvBi`W;>_wh=>|t`52R0jZjyN zrY$Xv02t8|BZ<+YZ|uq&HC|tYlO)k$;bmYG^xH4iCAE-*F8UqG8Gfm1-z>XER}1qfZ{XVn928-dd;=pb5OF`j%6)8{c@4Zxcvd8rZu%OGkyAk~ zP(Z$!( z-+w>XXvZqu)`5%71w9$`<<%Y!_koul{`taK@gRztSI~pr3^qswBU(7};E^iJ%If1r z(In1K{!a!A4u^P#$V+gv_*<_bus7UW7`Sp%Ad-=h6#5(af3JP@+K06saW1ZD89dEN^>!>!xMt5tknHmDQ0qX9C zJ}zw3t5@IEy$?}g9Pf5edPPYfJRdnm9pi9TvTM=L+64;22T z_1^v-MXT?SGazwz5tZ+ww7e~=O~ub2N~o(q-~Td?{6dy~Hp4n#wVtL8j2k5_#yGLN zQ_enkQ-q>8p*;+5AA!$6azuo%$JoTN7 zY}WK8SM!6Fpu*>YbBYZi48f=!pO&dHYe9nn@vYsc`HHy@_*@hAUvT{JVk{t*5kQ;L zvC|HfU)Hv}!lhW58u(z+8UH7n9HLt-Y3RLZd7JI>WmFzyd=krxpBNcca5uL@Kh4gd zZZ2EC7NPJfs91Q_B!iy z_HG&J)lzH(rSxL@1DCv9o>Jw=PC9B~8idg`u;!+=Pjmgh|B&m%l2HzSCJEqK9da@@ zf|=SiR*v;>H{`$7lsXq?R4&$?KLy?&oQ_@|g6W6cWY6#KTU#F4)Ry{L)C1@xWcCb8 zR|0!Q%&_+L9cD}oQ&3<)TEI;Zb+Jc~y5(Bax`mPOdao-Qz71tx?`wZ`=N_t(K14=e ze0gZe>q~1wUy=@Oftv){<)kmHtC}Jto5voymo|5}(O;R167acnX-D)^3H-d30*T%J zmeDO`UkOA>#_rn+(9V#3dxm(th2ddTrJ`EH{K72P$soX~OG1vMSPo(tWIvU}YkBms zSy^WHtT;4c4Go8&u8s68R35bG?J7|(3nySy(PQhhW~}EKG}}H<{MI|GQb0K&(&E|WuUG}3;UCM zcysVqO*wtg(VP}v{UOpv(=vm+Kff)N!iw9hB{E-3oonlgzA@1}2H!_ijycYUG7^Uy zj2x%TU`!=!4Z9S3xL#w%>pR>nE}jTX^)FRx_49<|VIMyRzCN7sc+raa@O<<)7kns+ z3Q3fduNZL0P9tJ%FnG@X%(v&GPdu#FcPOoQQQU=s>zn73hSVvPcDwp@% zM1e2O+TKs*!*w)H|4ww>=-5$FskGT|WM=v{5BJ!b_sDR2mFGtEZ?xe$BEVrKZmY1! z&Na@5V^x2{KXiD|oA4%KfoZyeF$?2M+J{iw3o;w$6EA34gq620Q2#cl?>nxdH^m-B zkgVQ{pskE%_>~WJ@4v-yGC()N8fr+>-u%ykyA$IOTzZ>#x5YO@(-`Gp+VtTfsVVIV zj1ORk3UN0bWtnCFVvyv}-J)ZBbyV8$pDSMKOkOki4Hyk9YE7A!+9f@8)j}OXtDyEt1^?nW zSbR)7J273$YCXxZeZ2}dU)gRC1VaVc?=g9~=-l<2YRbbt6XX8-o@-Meuxpk%{>@ddu$S|+9{|6`F^Edzi literal 0 HcmV?d00001 diff --git a/docs/source/notebooks/example.ipynb b/docs/source/notebooks/example.ipynb index eb22181..7b01a2b 100644 --- a/docs/source/notebooks/example.ipynb +++ b/docs/source/notebooks/example.ipynb @@ -5,7 +5,7 @@ "id": "2ebd6341-6ab2-4dbe-8fd2-fe235520af5f", "metadata": {}, "source": [ - "# Examples" + "# Example and features" ] }, { @@ -13,7 +13,24 @@ "id": "66ec8f0a-120e-4de7-85dc-69e7c1f84412", "metadata": {}, "source": [ - "Here are a few more examples of `calabru`" + "We will consider a bridge grillage model created using the `ospgrillage` module\n", + "as our running example to demonstrate the features of `calabru`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a20ddb77-e42a-498c-a5a4-7386f561bf82", + "metadata": {}, + "outputs": [], + "source": [ + "import calabru as clb # calabru package\n", + "import numpy as np # for numerical arrays\n", + "import matplotlib.pyplot as plt # for plotting\n", + "from IPython import display # For images in notebook\n", + "import pycba as cba # for creating beam model\n", + "import ospgrillage as og\n", + "%matplotlib inline \n" ] }, { @@ -21,61 +38,147 @@ "id": "4f64cddc-6ae4-41d1-b2ba-da14dc589fcc", "metadata": {}, "source": [ - "## Example 1 - Exploring input options" + "## Exploring parameter options" + ] + }, + { + "cell_type": "markdown", + "id": "e3a8fc08-682c-4b26-b00d-3463293703ea", + "metadata": {}, + "source": [ + "### Inputs" + ] + }, + { + "cell_type": "markdown", + "id": "d0a9bc72-15a7-4774-9f73-4c6512920628", + "metadata": {}, + "source": [ + "`calabru` takes multiple inputs for the updating parameters as a list." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "12c1c381-3c9d-434c-b923-bc3dbfb26285", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "start = [\n", + " 0.2, \n", + " 0.4,\n", + " 0.6,\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "ac1d3f25-5e83-4dc3-b49c-af3995eabac0", + "metadata": {}, + "source": [ + "We can introduce bounds which the parameters will not exceed during the calibration process as follows:" + ] }, { "cell_type": "code", - "execution_count": null, - "id": "eb813bc2-d3d1-4ce1-b27b-1199bf646a1e", + "execution_count": 3, + "id": "0889938c-3c0d-48f8-8003-cfbd05ea30e5", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "bounds = [\n", + " [0.1,0.5], # lower and upper bounds for first param \n", + " [0.7], # upper bound of second param, lower default to zero \n", + " [], # no bounds for third param\n", + " ]" + ] }, { "cell_type": "markdown", - "id": "c22aa21d-0366-4a04-90ab-50b7603c91ff", + "id": "52e86ec1-c980-413d-8787-c8330575bb3f", + "metadata": {}, + "source": [ + "where the `bounds` list must be the same size as the `start` list.\n", + "Each element should be a list of a lower and upper bound (second entry)." + ] + }, + { + "cell_type": "markdown", + "id": "b0ecc314-4e02-41f1-b757-9aa7cdded647", + "metadata": {}, + "source": [ + "### Targets" + ] + }, + { + "cell_type": "markdown", + "id": "81cfcfa9-ca1a-4798-9f51-beaae1f624ab", "metadata": {}, "source": [ - "## Example 2 - Grillage model problem in ospgrillage\n", + "Each target responses can be a list/array.\n", "\n", - "We have a single-span bridge we'd like to use to determine the bridge load effects due to an imposed load. In turn, a grillage model of a single-span bridge created using the `ospgrillage` package. \n" + "For example, we have can have the deflected shape list and the force magnitude of Element 5 as the first and second element the list of `target` respectively." ] }, { "cell_type": "code", - "execution_count": null, - "id": "371f2a7d-87e4-4e89-b8f0-ec966ac57639", + "execution_count": 4, + "id": "693bc990-4fb3-4c1d-9c34-d3cbd66db625", "metadata": {}, "outputs": [], "source": [ - "display.Image(\"./images/intro_ex_1.png\",width=800)" + "target = [\n", + " 5948.52, # element forces\n", + " [\n", + " 0.0,\n", + " 5.244e-05,\n", + " 9.984e-05,\n", + " 0.000136,\n", + " 0.0001558,\n", + " 0.0001558,\n", + " 0.000136,\n", + " 9.984e-05,\n", + " 5.243e-05,\n", + " 0.0,\n", + " ], # node displacements\n", + " \n", + "] " ] }, { "cell_type": "markdown", - "id": "7b01d2b4-86bc-4e3c-835a-e4bdb76ebc82", + "id": "c22aa21d-0366-4a04-90ab-50b7603c91ff", "metadata": {}, "source": [ - "Next, we want to update the model using experimental measurements of the bridge deflections. The measurement is defined as follows:\n" + "## Example 1 - Grillage model problem in ospgrillage\n", + "\n", + "We have a full-fledged single-span bridge model made using `ospgrillage` module that we'd like to use to determine the bridge load effects due to an imposed load.\n" ] }, { "cell_type": "code", - "execution_count": null, - "id": "f33e36ab-5091-4a91-b434-21fb771e9d37", + "execution_count": 11, + "id": "371f2a7d-87e4-4e89-b8f0-ec966ac57639", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": { + "image/png": { + "width": 800 + } + }, + "output_type": "execute_result" + } + ], "source": [ - "target_deflections = [[0.0, 5.24e-05, 9.98e-05, 0.000136, 0.000155,0.0001558, 0.000136, 9.98e-05, 5.24e-05,0.0]]" + "display.Image(\"../images/osp_example.png\",width=800)" ] }, { @@ -83,27 +186,57 @@ "id": "d787bca0-bd20-49cc-bb8d-66c7cb26d1dc", "metadata": {}, "source": [ - "We want to update the stiffness of the girders (`I`) in the model to update the model:" + "We want to update the moment of inertia of the longitudinal girders (`I`) of the bridge model. In addition, we are uncertain of the moment of inertia of the two edge members as well. Therefore, we introduce two updating paramters to the model as:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "50e8038b-93f7-43e3-8e7b-fa5b91f1f9ab", "metadata": {}, "outputs": [], "source": [ - "I_start = [0.2] # m4" + "start = [0.2, # longitudinal girders, I\n", + " 0.1, # edge member, I\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "7b01d2b4-86bc-4e3c-835a-e4bdb76ebc82", + "metadata": {}, + "source": [ + "We update the model using some \"known\" measurements of the bridge deflections. For this,the measurements is taken as the\n", + "responses which corresponds to a parameter list = [0.5,0.1]\n" ] }, { "cell_type": "code", - "execution_count": null, - "id": "7ba40eb6-316e-4d56-881b-3c87c93a234a", + "execution_count": 7, + "id": "d67b5834-8f84-4997-8106-18a2157f8811", "metadata": {}, "outputs": [], "source": [ - "First we need to structure the model's generation and analysis script into a function handler (denoted as `main()`) with the following properties:\n", + "target = [[1047.057906932444,\n", + " [0.0,\n", + " 3.847756717425916e-05,\n", + " 7.335795722107879e-05,\n", + " 0.0001001430188545662,\n", + " 0.00011472208165921942,\n", + " 0.00011472208165922035,\n", + " 0.00010014301885456844,\n", + " 7.335795722108123e-05,\n", + " 3.847756717426085e-05,\n", + " 0.0]]\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "05734b9f-1e03-42a7-94fe-895889115884", + "metadata": {}, + "source": [ + "Lets create the function handler (denote as `main()`) that creates and analyse the model with the following properties that is compatible with`calabru` to allow for updating procedures:\n", "\n", "1. `main()` takes in `I_start` as an argument.\n", "2. `main()` returns a list of the corresponding measurables of `target_deflections` from the model." @@ -111,16 +244,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "989b4a2c-4fd5-4111-b9a7-b9dce37ec2b6", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "def beam_with_patch_load_including_deflected_shape_output(p_matrix: list):\n", + "def main(p_matrix: list):\n", " # sort parameter variable\n", - " #P = p_matrix[0]\n", + "\n", " P = 1000\n", - " Iz = p_matrix[0]\n", + " Iz1 = p_matrix[0]\n", + " Iz2 = p_matrix[1]\n", "\n", " # Adopted units: N and m\n", " kilo = 1e3\n", @@ -156,7 +292,7 @@ " edge_longitudinal_section = og.create_section(\n", " A=0.934 * m2,\n", " J=0.1857 * m3,\n", - " Iz=0.3478 * m4,\n", + " Iz=Iz2 * m4,\n", " Iy=0.213602 * m4,\n", " Az=0.444795 * m2,\n", " Ay=0.258704 * m2,\n", @@ -165,7 +301,7 @@ " longitudinal_section = og.create_section(\n", " A=1.025 * m2,\n", " J=0.1878 * m3,\n", - " Iz=Iz * m4,\n", + " Iz=Iz1 * m4,\n", " Iy=0.113887e-3 * m4,\n", " Az=0.0371929 * m2,\n", " Ay=0.0371902 * m2,\n", @@ -256,10 +392,53 @@ " results = simple_bridge.get_results()\n", "\n", " # arbitrary force components\n", - " r_mat = [[og.ops.nodeDisp(n)[1] for n in [2,9,16,23,30,37,44,51,58,65]]]\n", - " #og.ops.eleForce(25)[1],\n", + " r_mat = [[og.ops.eleForce(25)[1],[og.ops.nodeDisp(n)[1] for n in [2,9,16,23,30,37,44,51,58,65]]]]\n", + "\n", " return r_mat" ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "50e8e494-9924-413c-867e-0b7383e861a4", + "metadata": {}, + "outputs": [], + "source": [ + "simple_beam_updating = clb.ModelUpdating(\n", + " function_handle=main,\n", + " param_list=start,\n", + " target_list=target,\n", + " max_error=0.1,\n", + " write_output_txt=False\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a1f0bdc8-307c-4fad-8be8-e7a65c339363", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0.2, 0.1], [0.3365125562453617, 0.10119151305405859], [0.45716219684186105, 0.1008159604001884], [0.5002470885555945, 0.10009323201609568]]\n" + ] + } + ], + "source": [ + "simple_beam_updating.update_model()\n", + "print(simple_beam_updating.param_update_history)" + ] + }, + { + "cell_type": "markdown", + "id": "ddf76bc8-59ac-463a-bb05-c7d8ae89c612", + "metadata": {}, + "source": [ + "As can be seen the values converged to [0.5,0.1] " + ] } ], "metadata": { diff --git a/tests/fixtures.py b/tests/fixtures.py index 18e24e1..b6a6620 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -159,6 +159,150 @@ def beam_with_patch_load(p_matrix: list): return r_mat +def main(p_matrix: list): + # sort parameter variable + + P = 1000 + Iz1 = p_matrix[0] + Iz2 = p_matrix[1] + + # Adopted units: N and m + kilo = 1e3 + milli = 1e-3 + N = 1 + m = 1 + mm = milli * m + m2 = m ** 2 + m3 = m ** 3 + m4 = m ** 4 + kN = kilo * N + MPa = N / ((mm) ** 2) + GPa = kilo * MPa + + # parameters of bridge grillage + L = 10 * m # span + w = 5 * m # width + n_l = 7 # number of longitudinal members + n_t = 10 # number of transverse members + edge_dist = 1 * m # distance between edge beam and first exterior beam + ext_to_int_dist = ( + 2.2775 * m + ) # distance between first exterior beam and first interior beam + angle = 0 # skew angle + mesh_type = "Oblique" + + # define material + concrete = og.create_material( + material="concrete", code="AS5100-2017", grade="65MPa" + ) + + # define sections (parameters from LUSAS model) + edge_longitudinal_section = og.create_section( + A=0.934 * m2, + J=0.1857 * m3, + Iz=Iz2 * m4, + Iy=0.213602 * m4, + Az=0.444795 * m2, + Ay=0.258704 * m2, + ) + + longitudinal_section = og.create_section( + A=1.025 * m2, + J=0.1878 * m3, + Iz=Iz1 * m4, + Iy=0.113887e-3 * m4, + Az=0.0371929 * m2, + Ay=0.0371902 * m2, + ) + + transverse_section = og.create_section( + A=0.504 * m2, + J=5.22303e-3 * m3, + Iy=0.32928 * m4, + Iz=1.3608e-3 * m4, + Ay=0.42 * m2, + Az=0.42 * m2, + ) + + end_transverse_section = og.create_section( + A=0.504 / 2 * m2, + J=2.5012e-3 * m3, + Iy=0.04116 * m4, + Iz=0.6804e-3 * m4, + Ay=0.21 * m2, + Az=0.21 * m2, + ) + + # define grillage members + longitudinal_beam = og.create_member( + section=longitudinal_section, material=concrete + ) + edge_longitudinal_beam = og.create_member( + section=edge_longitudinal_section, material=concrete + ) + transverse_slab = og.create_member(section=transverse_section, material=concrete) + end_transverse_slab = og.create_member( + section=end_transverse_section, material=concrete + ) + + # create grillage + simple_bridge = og.create_grillage( + bridge_name="simple_bridge", + long_dim=L, + width=w, + skew=angle, + num_long_grid=n_l, + num_trans_grid=n_t, + edge_beam_dist=edge_dist, + mesh_type=mesh_type, + ) + + simple_bridge.set_member(longitudinal_beam, member="interior_main_beam") + simple_bridge.set_member(longitudinal_beam, member="exterior_main_beam_1") + simple_bridge.set_member(longitudinal_beam, member="exterior_main_beam_2") + simple_bridge.set_member(edge_longitudinal_beam, member="edge_beam") + simple_bridge.set_member(transverse_slab, member="transverse_slab") + simple_bridge.set_member(end_transverse_slab, member="start_edge") + simple_bridge.set_member(end_transverse_slab, member="end_edge") + simple_bridge.create_osp_model(pyfile=False) + og.opsplt.plot_model() + # add load case + # Patch load over entire bridge deck (P is kN/m2) + P = P * kN / m2 # magnitude of patch vertex + patch_point_1 = og.create_load_vertex(x=0, z=0, p=P) + patch_point_2 = og.create_load_vertex(x=L, z=0, p=P) + patch_point_3 = og.create_load_vertex(x=L, z=w, p=P) + patch_point_4 = og.create_load_vertex(x=0, z=w, p=P) + test_patch_load = og.create_load( + loadtype="patch", + name="Test Load", + point1=patch_point_1, + point2=patch_point_2, + point3=patch_point_3, + point4=patch_point_4, + ) + + test_point_load = og.create_load( + loadtype="point", + name="Test Load", + point1=og.create_load_vertex(x=L / 2, z=w / 2, p=P), + ) + + # Create load case, add loads, and assign + patch_case = og.create_load_case(name="test patch load case") + patch_case.add_load(test_patch_load) + point_case = og.create_load_case(name="test point load case") + point_case.add_load(test_point_load) + # sn8474.add_load_case(patch_case) + simple_bridge.add_load_case(point_case) + + simple_bridge.analyze() + results = simple_bridge.get_results() + + # arbitrary force components + r_mat = [[og.ops.eleForce(25)[1],[og.ops.nodeDisp(n)[1] for n in [2,9,16,23,30,37,44,51,58,65]]]] + + return r_mat def beam_with_patch_load_including_deflected_shape_output(p_matrix: list): """ diff --git a/tests/test_updating.py b/tests/test_updating.py index 3ce5efb..1c67a4e 100644 --- a/tests/test_updating.py +++ b/tests/test_updating.py @@ -34,6 +34,34 @@ def test_basic_update(): ) +def test_main(): + start = [0.2, # load, P + 0.1, # moment of inertia, I + ] + target = [[1047.057906932444, + [0.0, + 3.847756717425916e-05, + 7.335795722107879e-05, + 0.0001001430188545662, + 0.00011472208165921942, + 0.00011472208165922035, + 0.00010014301885456844, + 7.335795722108123e-05, + 3.847756717426085e-05, + 0.0]]] + # node displacements + + simple_beam_updating = ModelUpdating( + function_handle=fixtures.main, + param_list=start, + target_list=target, + max_error=0.1, + write_output_txt=False + ) + simple_beam_updating.update_model() + print(simple_beam_updating.param_update_history) + + def test_target_resp_as_list(): """ Checks updating using a list of measurements as an element entry of the target measurement. The updating should From a165375243f31003fef8fbb8ba4f9b801f7047a6 Mon Sep 17 00:00:00 2001 From: jngan Date: Wed, 15 May 2024 15:31:36 +1000 Subject: [PATCH 2/3] docs: modify sphinx settings --- calabru/__init__.py | 3 + calabru/calibrator.py | 246 ++++----- calabru/helpers.py | 135 +++++ docs/requirement.txt | 4 +- docs/source/api.rst | 10 +- docs/source/conf.py | 16 +- docs/source/images/logo.png | 0 docs/source/index.rst | 26 +- docs/source/installation.md | 4 +- .../notebooks/ospgrillage_example.ipynb | 465 ++++++++++++++++++ pyproject.toml | 4 +- 11 files changed, 736 insertions(+), 177 deletions(-) create mode 100644 calabru/helpers.py create mode 100644 docs/source/images/logo.png create mode 100644 docs/source/notebooks/ospgrillage_example.ipynb diff --git a/calabru/__init__.py b/calabru/__init__.py index eed70c9..50ec9eb 100644 --- a/calabru/__init__.py +++ b/calabru/__init__.py @@ -1 +1,4 @@ +__version__ = "0.1.0" + from .calibrator import * +from .helpers import * diff --git a/calabru/calibrator.py b/calabru/calibrator.py index 9a999de..e41e440 100644 --- a/calabru/calibrator.py +++ b/calabru/calibrator.py @@ -2,36 +2,47 @@ """ Main calibration module """ -import numpy as np from datetime import datetime import copy -from scipy.interpolate import interp1d -import matplotlib.pyplot as plt +from helpers import * class ModelUpdating: """ - Main updating/calibrating class. + Main class to handle updating. """ def __init__(self, function_handle, **kwargs): """ - :param function_handle: Function handler to create and analyze models in Python environment. Note the function - handler must be able to pass in updating parameters and return desirable responses. - :param sensitivity_type: Method to obtain the sensitivity matrix. Default "FDM" - :type sensitivity_type: str - :param param_list: A list of float or int of starting values of updating parameters. - :type param_list: list - :param target_list: A list of float or int of target/objectives of the updating function handler. - :type target_list: list - :param target_resp_list: Multi dimension list of k considered models/cases. If a single dimension list is provided - the class parses the list into a mutli dimension 1x(k=1) list. - - :param max_increm_steps: Maximum updating increments. Default 50 - :param param_increm_rate: Increment rate of parameters between each step. Default 10% - :param max_error: Maximum allowable parameter error. + Parameters + ---------- + function_handle: + Python function handler to calibrate. + **kwargs: dict, optional + Extra arguments for class and function_handle. Refer below for the list of all possible arguments. + + Other Parameters + ---------------- + iterative_method: str, default="FDM" + Method to calculate sensitivity matrix. + param_list: list + A list of starting values for updating parameters + target_list: list + A list of target/objective values for the function handle outputs + target_resp_list: list + Multi dimension list of k considered models/cases. If a single dimension list is provided + the class parses the list into a mutli dimension 1x(k=1) list. + max_increm_steps: int, default=50 + Maximum updating increments + param_increm_rate: float, default=1.1 + Increment rate of parameter between updating iterations + max_error: float + maximum allowable parameter error + write_output_txt: bool + If true, writes + """ # get model and load case inputs @@ -48,8 +59,14 @@ def __init__(self, function_handle, **kwargs): "param_bounds_list", [[] for item in self.param_list] ) # bounds for params # empty list means no bounds. + # weighting for param bounds + self.param_sen_weighting = kwargs.get("param_sen_weighting", [1 for item in self.param_list]) + if not self.param_sen_weighting: + self.param_sen_weighting = [1 for item in self.param_list] + + - # check validity of param bounds + # check validity of param bounds if len(self.param_list) != len(self.param_bounds_list): raise Exception( "Param bound list must match the number of parameters: Hint specify empty list [] to params that are not bounded" @@ -102,17 +119,34 @@ def __init__(self, function_handle, **kwargs): def set_targets(self, target_list: list): """ Set or overwrite updating parameters. - :param target_list: list of target response value. Note: list order must correspond to the outputs returned + + Parameters + ---------- + target_list: list + ist of target response value + + Notes + ----- + list order must correspond to the outputs returned by main() function. Refer to template main() function for information on setting up the updating procedure. - :type target_list: list + """ self.target_response_list = target_list def set_param(self, param_list: list, variance_range=None): """ Set or overwrite updating parameters. - :param param_list: list of starting parameter values. Note: list order must correspond to the input of + + Parameters + ---------- + param_list: list + list of starting parameter values + + Notes + ----- + Note: list order must correspond to the input of main() updating function. Refer to template main() function for information on setting up the updating procedure. + """ self.param_list = param_list @@ -120,7 +154,10 @@ def update_model(self, **kwargs): """ Calibrate the model. - Keyword arguments passed under this function are passed to function handle of the updating object. + Parameters + ---------- + **kwargs: dict, optional + Keyword arguments accepted by the function handler of the updating Example: If the function handler takes two keyword arguments - @@ -146,7 +183,7 @@ def update_model(self, **kwargs): self.global_sensitivity_matrix += self.sensitivity_matrix self.global_resp_diff += self.resp_diff - esti = self._get_pseudo_inv_estimation( + esti = get_pseudo_inv_estimation( sens_mat=self.global_sensitivity_matrix, resp_diff=self.global_resp_diff ) # compute residue and check threshold @@ -206,15 +243,24 @@ def update_model(self, **kwargs): def _compute_fdm_sensitivity(self, param_list, target_resp=None, model_index=0): """ - Function to compute sensitivity matrix based on finite difference sensitivity method. The function runs the + Returns the sensitivity matrix based on finite difference sensitivity method. The function runs the function handle defined during construction of class with the initial parameters as inputs. Then increments the parameter values to obtain an incremental responses. Subsequently, assembles the sensitivity matrix. - :param param_list: Parameters at current updating step. - :type param_list:list - :param model_index: Index of output from function_handle which matches the current evaluating target response. + Parameters + ---------- + param_list: list + list of updating parameter values + target_resp: list, optional + list of target responses + model_index: int, default=0 + Index of output from function_handle which matches the current evaluating target response + + Returns + ------- + Array like + Array of sensitivity matrix - also stored as `sensitivity_matrix` in class - :returns array of sensitivity matrix stored in sensitivity_matrix var """ # get base response @@ -244,11 +290,11 @@ def _compute_fdm_sensitivity(self, param_list, target_resp=None, model_index=0): model_time = list(response[model_index][k].keys()) if len(ref_resp) > len(response): - interp_ref_resp = self._interpolate_measurements( + interp_ref_resp = interpolate_measurements( data_x=time, data_y=val, model_x=model_time ) else: - interp_ref_resp = self._interpolate_measurements( + interp_ref_resp = interpolate_measurements( data_x=model_time, data_y=val, model_x=time ) else: @@ -256,13 +302,13 @@ def _compute_fdm_sensitivity(self, param_list, target_resp=None, model_index=0): model_abs_axis = np.linspace(0, 1, len(kth_model_response)) abs_time_measure = np.linspace(0, 1, len(ref_resp)) - interp_ref_resp = self._interpolate_measurements( + interp_ref_resp = interpolate_measurements( data_x=abs_time_measure, data_y=ref_resp, model_x=model_abs_axis ) # plt.plot(model_abs_axis, interp_ref_resp) # plt.plot(model_abs_axis, kth_model_response) # plt.show() - rmse = self._calculate_rmse( + rmse = calculate_rmse( ref_response_list=interp_ref_resp, current_response_list=kth_model_response, ) @@ -288,25 +334,33 @@ def _compute_fdm_sensitivity(self, param_list, target_resp=None, model_index=0): # checks if the current response is a list if hasattr(target_resp[i], "__len__"): # calculate rmse - rmse = self._calculate_rmse( + rmse = calculate_rmse( ref_response_list=inc_response[model_index][i], current_response_list=response[model_index][i], ) self.sensitivity_matrix[i].append( - rmse / (param * abs(self.increment_rate - 1)) + rmse / (param * abs(self.increment_rate - 1)*self.param_sen_weighting[j]) ) else: self.sensitivity_matrix[i].append( - (inc_response[model_index][i] - response[model_index][i]) + (inc_response[model_index][i] - response[model_index][i]) * self.param_sen_weighting[j] / (param * abs(self.increment_rate - 1)) ) def get_updated_response(self, param_list): + """Returns the responses from a given list of parameters + Parameters + ---------- + param_list: list + List of parameter values + + """ # get base response return self.function_handle(param_list, **self.kwarg) def print_to(self, current_step, error): + """Prints the status of each step""" # function to print updating status to print("Curent update step {}".format(current_step)) print(self.param_update_history[-1]) @@ -314,6 +368,7 @@ def print_to(self, current_step, error): print(error) def _write_output_txt(self): + """Returns a report .txt file of the calibration process""" name = self.name + ".txt" with open(name, "w") as file_handle: # create py file or overwrite existing @@ -335,122 +390,3 @@ def _write_output_txt(self): file_handle.write("Target response\n") file_handle.write(str(self.target_response_list) + "\n") - - @staticmethod - def _get_pseudo_inv_estimation(sens_mat, resp_diff): - """ - Function to estimate parameters for model updating using Pseudo Inverse Method - :param sens_mat: sensitivity matrix at current updating step - :type sens_mat: list of size r by p where r and p are the number of responses and parameters respectively - """ - sens_mat_transpose = np.transpose(sens_mat) - resp_num = np.array(sens_mat).shape[0] - param_num = np.array(sens_mat).shape[1] - # init var - estimate = None - if resp_num == param_num: - estimate = np.dot(np.linalg.inv(sens_mat), resp_diff) - elif resp_num > param_num: - pseudo_inv = np.dot( - np.linalg.inv(np.dot(sens_mat_transpose, sens_mat)), sens_mat_transpose - ) - estimate = np.dot(pseudo_inv, resp_diff) - elif resp_num < param_num: - pseudo_inv = np.dot( - sens_mat_transpose, - np.linalg.inv( - np.dot( - sens_mat, - sens_mat_transpose, - ) - ), - ) - estimate = np.dot(pseudo_inv, resp_diff) - - return estimate - - @staticmethod - def _calculate_rmse(ref_response_list, current_response_list): - N = len(ref_response_list) - - return np.sqrt( - sum( - [ - (ref - current) ** 2 / N - for (ref, current) in zip(ref_response_list, current_response_list) - ] - ) - ) - - @staticmethod - def _get_bayesian_param_estimation(sens_mat, resp_diff, current_param, cp, cr): - """ - Function to perform parameter estimation using Bayesian approach. Here, a gain matrix G is calculated - from the provided confidence weighing for parameter and responses. - :param current_param: - :param cp: - :parm cr: - """ - sens_mat_transpose = np.transpose(sens_mat) - resp_num = np.array(sens_mat).shape[0] - param_num = np.array(sens_mat).shape[1] - - # init var - gain_mat = [] - estimate = None - if resp_num >= param_num: - gain_mat = np.dot( - np.dot( - np.linalg.inv( - cp + np.dot(np.dot(sens_mat_transpose, cr), sens_mat) - ), - sens_mat_transpose, - ), - cr, - ) - - elif resp_num < param_num: - cp_inv = np.linalg.inv(cp) - cr_inv = np.linalg.inv(cr) - gain_mat = np.dot( - np.dot(cp_inv, sens_mat_transpose), - np.linalg.inv( - cr_inv + np.dot(np.dot(sens_mat, cp_inv), sens_mat_transpose) - ), - ) - - else: - raise Exception("Bayesian parameters error") - estimate = [ - p + gr for (p, gr) in zip(current_param, np.dot(gain_mat, -resp_diff)) - ] - return estimate - - def get_updating_outputs(self): - """ - Extracts information of the updating procedure - - :return: - """ - if self.update: - pass - else: - pass - - @staticmethod - def _interpolate_measurements(data_x, data_y, model_x): - """ - Function to interpolate measurement points on numerical/system model given vectors of measurement (1) time seires - , and (2) values. - - This function is used when length missmatch between measurement vector and model output vector. - - """ - # takes in a vector of common x axis e.g. time ratio of positional times over total movement time window (0 to 1) - - # create interp function using measurment data - linear interp - f1 = interp1d(data_x, data_y) - - # apply interp function to ospgrillage data to get respctive positional strain values - return f1(model_x) - # return the decimated curve value diff --git a/calabru/helpers.py b/calabru/helpers.py new file mode 100644 index 0000000..0a83b2c --- /dev/null +++ b/calabru/helpers.py @@ -0,0 +1,135 @@ +import numpy as np +from scipy.interpolate import interp1d +def get_pseudo_inv_estimation(sens_mat, resp_diff): + """ + Estimate parameters for model updating using Pseudo Inverse Method + + Parameters + ---------- + sens_mat: array_like + Sensitivity matrix + resp_diff: list + list of response differences value + + Notes + ----- + The array sizes much match. list of size r by p where r and p are the number of responses and parameters respectively + """ + sens_mat_transpose = np.transpose(sens_mat) + resp_num = np.array(sens_mat).shape[0] + param_num = np.array(sens_mat).shape[1] + # init var + estimate = None + if resp_num == param_num: + estimate = np.dot(np.linalg.inv(sens_mat), resp_diff) + elif resp_num > param_num: + pseudo_inv = np.dot( + np.linalg.inv(np.dot(sens_mat_transpose, sens_mat)), sens_mat_transpose + ) + estimate = np.dot(pseudo_inv, resp_diff) + elif resp_num < param_num: + pseudo_inv = np.dot( + sens_mat_transpose, + np.linalg.inv( + np.dot( + sens_mat, + sens_mat_transpose, + ) + ), + ) + estimate = np.dot(pseudo_inv, resp_diff) + + return estimate + +def calculate_rmse(ref_response_list, current_response_list): + """Get the root mean square error (RMSE) between the reference and current response values + Parameters + ---------- + ref_response_list: list + list of reference response values + current_response_list: list + list of current response values + + Returns + ------- + float + Root mean square error + + """ + N = len(ref_response_list) + + return np.sqrt( + sum( + [ + (ref - current) ** 2 / N + for (ref, current) in zip(ref_response_list, current_response_list) + ] + ) + ) + +def get_bayesian_param_estimation(sens_mat, resp_diff, current_param, cp, cr): + """ + Function to perform parameter estimation using Bayesian approach. Here, a gain matrix G is calculated + from the provided confidence weighing for parameter and responses. + :param current_param: + :param cp: + :parm cr: + """ + sens_mat_transpose = np.transpose(sens_mat) + resp_num = np.array(sens_mat).shape[0] + param_num = np.array(sens_mat).shape[1] + + # init var + gain_mat = [] + estimate = None + if resp_num >= param_num: + gain_mat = np.dot( + np.dot( + np.linalg.inv( + cp + np.dot(np.dot(sens_mat_transpose, cr), sens_mat) + ), + sens_mat_transpose, + ), + cr, + ) + + elif resp_num < param_num: + cp_inv = np.linalg.inv(cp) + cr_inv = np.linalg.inv(cr) + gain_mat = np.dot( + np.dot(cp_inv, sens_mat_transpose), + np.linalg.inv( + cr_inv + np.dot(np.dot(sens_mat, cp_inv), sens_mat_transpose) + ), + ) + + else: + raise Exception("Bayesian parameters error") + estimate = [ + p + gr for (p, gr) in zip(current_param, np.dot(gain_mat, -resp_diff)) + ] + return estimate + + +def interpolate_measurements(data_x, data_y, model_x): + """ + Returns the interpolation for set of data for a given value, x. + + Parameters + ---------- + + + Function to interpolate measurement points on numerical/system model given vectors of measurement (1) time seires + , and (2) values. + + This function is used when length missmatch between measurement vector and model output vector. + + """ + # takes in a vector of common x axis e.g. time ratio of positional times over total movement time window (0 to 1) + + # create interp function using measurment data - linear interp + f1 = interp1d(data_x, data_y) + + # apply interp function to ospgrillage data to get respctive positional strain values + return f1(model_x) + # return the decimated curve value diff --git a/docs/requirement.txt b/docs/requirement.txt index 179d091..431240c 100644 --- a/docs/requirement.txt +++ b/docs/requirement.txt @@ -4,11 +4,11 @@ pytest>=6.1.1 datetime scipy pydata-sphinx-theme -Sphinx>=4.0 +Sphinx>=5.0 nbsphinx sphinx-autodoc-typehints pandoc markupsafe==2.0.1 pygments >= 2.7 -PyCBA +pycba ospgrillage \ No newline at end of file diff --git a/docs/source/api.rst b/docs/source/api.rst index cdb149f..395856e 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -1,7 +1,13 @@ +API Reference +============= + +Package Modules +--------------- + .. autosummary:: :toctree: gen - :template: custom-module-template.rst :recursive: - calabru.ModelUpdating + calabru.calibrator + calabru.helpers diff --git a/docs/source/conf.py b/docs/source/conf.py index 3a50cb8..0fa483c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,8 +13,9 @@ import os import sys -sys.path.insert(0, os.path.abspath("../../")) - +sys.path.insert(0, os.path.abspath("../../calabru/")) +from calabru import __version__ as ver +# # -- Project information ----------------------------------------------------- @@ -23,7 +24,12 @@ author = "Colin Caprani, Jun Wei Ngan" # The full version, including alpha/beta/rc tags -release = "0.1" +# The short Major.Minor.Build version +_v = ver.split(".") +_build = "".join([c for c in _v[2] if c.isdigit()]) +version = _v[0] + "." + _v[1] + "." + _build +release = ver + # -- General configuration --------------------------------------------------- @@ -81,7 +87,7 @@ "icon_links": [ { "name": "GitHub", - "url": "https://github.com/ccaprani/pycba", + "url": "https://github.com/MonashSmartStructures/calabru", "icon": "fab fa-github-square", }, { @@ -101,7 +107,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -# html_logo = "./images/logo.png" +html_logo = "./images/logo.png" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". diff --git a/docs/source/images/logo.png b/docs/source/images/logo.png new file mode 100644 index 0000000..e69de29 diff --git a/docs/source/index.rst b/docs/source/index.rst index 9a82c60..f72c43b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,25 +1,33 @@ -Calabru -======= -`calabru` [1]_ is a calibration framework for model/analysis/data systems in the Python -environment. +Welcome to calabru's documentation! +=================================== +`calabru` [1]_ is a calibration framework in the Python environment.`calabru` is provides fast calibration of general model/functions/systems in Python environment. -The calibration framework includes several state-of-the-art model updating methods such as: + +`calabru` uses several state-of-the-art model updating methods such as: - Sensitivity-based analysis -- Bayesian-based approach (in progress) +- Bayesian-based approach .. [1] Fun fact, "Calabru" means Calibration in the Irish language. -Documentation -============= - .. toctree:: :maxdepth: 2 + :caption: Contents: + installation + api notebooks/intro notebooks/example + + +Related Packages +================ +- `pycba `_ is an analysis package for continuous beam analysis. +- `sectionproperties `_ is a package for the analysis of cross-sectional geometric properties and stress distributions. +- `ospgrillage `_ is a bridge deck grillage analysis package which is a pre-processor for `OpenSeesPy `_, a python wrapper for the general finite element analysis framework `OpenSees `_. + Indices and tables ================== diff --git a/docs/source/installation.md b/docs/source/installation.md index 7baaf2f..546b312 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -5,8 +5,6 @@ Required Dependencies --------------------- - Python 3.8 or later - numpy -- scipy -- matplotlib Instructions ------------ @@ -24,7 +22,7 @@ For contributions, first fork the repo and clone from your fork. `Here " + ] + }, + "execution_count": 11, + "metadata": { + "image/png": { + "width": 800 + } + }, + "output_type": "execute_result" + } + ], + "source": [ + "display.Image(\"../images/osp_example.png\",width=800)" + ] + }, + { + "cell_type": "markdown", + "id": "d787bca0-bd20-49cc-bb8d-66c7cb26d1dc", + "metadata": {}, + "source": [ + "We want to update the moment of inertia of the longitudinal girders (`I`) of the bridge model. In addition, we are uncertain of the moment of inertia of the two edge members as well. Therefore, we introduce two updating paramters to the model as:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "50e8038b-93f7-43e3-8e7b-fa5b91f1f9ab", + "metadata": {}, + "outputs": [], + "source": [ + "start = [0.2, # longitudinal girders, I\n", + " 0.1, # edge member, I\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "id": "7b01d2b4-86bc-4e3c-835a-e4bdb76ebc82", + "metadata": {}, + "source": [ + "We update the model using some \"known\" measurements of the bridge deflections. For this,the measurements is taken as the\n", + "responses which corresponds to a parameter list = [0.5,0.1]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "d67b5834-8f84-4997-8106-18a2157f8811", + "metadata": {}, + "outputs": [], + "source": [ + "target = [[1047.057906932444,\n", + " [0.0,\n", + " 3.847756717425916e-05,\n", + " 7.335795722107879e-05,\n", + " 0.0001001430188545662,\n", + " 0.00011472208165921942,\n", + " 0.00011472208165922035,\n", + " 0.00010014301885456844,\n", + " 7.335795722108123e-05,\n", + " 3.847756717426085e-05,\n", + " 0.0]]\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "05734b9f-1e03-42a7-94fe-895889115884", + "metadata": {}, + "source": [ + "Lets create the function handler (denote as `main()`) that creates and analyse the model with the following properties that is compatible with`calabru` to allow for updating procedures:\n", + "\n", + "1. `main()` takes in `I_start` as an argument.\n", + "2. `main()` returns a list of the corresponding measurables of `target_deflections` from the model." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "989b4a2c-4fd5-4111-b9a7-b9dce37ec2b6", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def main(p_matrix: list):\n", + " # sort parameter variable\n", + "\n", + " P = 1000\n", + " Iz1 = p_matrix[0]\n", + " Iz2 = p_matrix[1]\n", + "\n", + " # Adopted units: N and m\n", + " kilo = 1e3\n", + " milli = 1e-3\n", + " N = 1\n", + " m = 1\n", + " mm = milli * m\n", + " m2 = m ** 2\n", + " m3 = m ** 3\n", + " m4 = m ** 4\n", + " kN = kilo * N\n", + " MPa = N / ((mm) ** 2)\n", + " GPa = kilo * MPa\n", + "\n", + " # parameters of bridge grillage\n", + " L = 10 * m # span\n", + " w = 5 * m # width\n", + " n_l = 7 # number of longitudinal members\n", + " n_t = 10 # number of transverse members\n", + " edge_dist = 1 * m # distance between edge beam and first exterior beam\n", + " ext_to_int_dist = (\n", + " 2.2775 * m\n", + " ) # distance between first exterior beam and first interior beam\n", + " angle = 0 # skew angle\n", + " mesh_type = \"Oblique\"\n", + "\n", + " # define material\n", + " concrete = og.create_material(\n", + " material=\"concrete\", code=\"AS5100-2017\", grade=\"65MPa\"\n", + " )\n", + "\n", + " # define sections (parameters from LUSAS model)\n", + " edge_longitudinal_section = og.create_section(\n", + " A=0.934 * m2,\n", + " J=0.1857 * m3,\n", + " Iz=Iz2 * m4,\n", + " Iy=0.213602 * m4,\n", + " Az=0.444795 * m2,\n", + " Ay=0.258704 * m2,\n", + " )\n", + "\n", + " longitudinal_section = og.create_section(\n", + " A=1.025 * m2,\n", + " J=0.1878 * m3,\n", + " Iz=Iz1 * m4,\n", + " Iy=0.113887e-3 * m4,\n", + " Az=0.0371929 * m2,\n", + " Ay=0.0371902 * m2,\n", + " )\n", + "\n", + " transverse_section = og.create_section(\n", + " A=0.504 * m2,\n", + " J=5.22303e-3 * m3,\n", + " Iy=0.32928 * m4,\n", + " Iz=1.3608e-3 * m4,\n", + " Ay=0.42 * m2,\n", + " Az=0.42 * m2,\n", + " )\n", + "\n", + " end_transverse_section = og.create_section(\n", + " A=0.504 / 2 * m2,\n", + " J=2.5012e-3 * m3,\n", + " Iy=0.04116 * m4,\n", + " Iz=0.6804e-3 * m4,\n", + " Ay=0.21 * m2,\n", + " Az=0.21 * m2,\n", + " )\n", + "\n", + " # define grillage members\n", + " longitudinal_beam = og.create_member(\n", + " section=longitudinal_section, material=concrete\n", + " )\n", + " edge_longitudinal_beam = og.create_member(\n", + " section=edge_longitudinal_section, material=concrete\n", + " )\n", + " transverse_slab = og.create_member(section=transverse_section, material=concrete)\n", + " end_transverse_slab = og.create_member(\n", + " section=end_transverse_section, material=concrete\n", + " )\n", + "\n", + " # create grillage\n", + " simple_bridge = og.create_grillage(\n", + " bridge_name=\"simple_bridge\",\n", + " long_dim=L,\n", + " width=w,\n", + " skew=angle,\n", + " num_long_grid=n_l,\n", + " num_trans_grid=n_t,\n", + " edge_beam_dist=edge_dist,\n", + " mesh_type=mesh_type,\n", + " )\n", + "\n", + " simple_bridge.set_member(longitudinal_beam, member=\"interior_main_beam\")\n", + " simple_bridge.set_member(longitudinal_beam, member=\"exterior_main_beam_1\")\n", + " simple_bridge.set_member(longitudinal_beam, member=\"exterior_main_beam_2\")\n", + " simple_bridge.set_member(edge_longitudinal_beam, member=\"edge_beam\")\n", + " simple_bridge.set_member(transverse_slab, member=\"transverse_slab\")\n", + " simple_bridge.set_member(end_transverse_slab, member=\"start_edge\")\n", + " simple_bridge.set_member(end_transverse_slab, member=\"end_edge\")\n", + " simple_bridge.create_osp_model(pyfile=False)\n", + "\n", + " # add load case\n", + " # Patch load over entire bridge deck (P is kN/m2)\n", + " P = P * kN / m2 # magnitude of patch vertex\n", + " patch_point_1 = og.create_load_vertex(x=0, z=0, p=P)\n", + " patch_point_2 = og.create_load_vertex(x=L, z=0, p=P)\n", + " patch_point_3 = og.create_load_vertex(x=L, z=w, p=P)\n", + " patch_point_4 = og.create_load_vertex(x=0, z=w, p=P)\n", + " test_patch_load = og.create_load(\n", + " loadtype=\"patch\",\n", + " name=\"Test Load\",\n", + " point1=patch_point_1,\n", + " point2=patch_point_2,\n", + " point3=patch_point_3,\n", + " point4=patch_point_4,\n", + " )\n", + "\n", + " test_point_load = og.create_load(\n", + " loadtype=\"point\",\n", + " name=\"Test Load\",\n", + " point1=og.create_load_vertex(x=L / 2, z=w / 2, p=P),\n", + " )\n", + "\n", + " # Create load case, add loads, and assign\n", + " patch_case = og.create_load_case(name=\"test patch load case\")\n", + " patch_case.add_load(test_patch_load)\n", + " point_case = og.create_load_case(name=\"test point load case\")\n", + " point_case.add_load(test_point_load)\n", + " # sn8474.add_load_case(patch_case)\n", + " simple_bridge.add_load_case(point_case)\n", + "\n", + " simple_bridge.analyze()\n", + " results = simple_bridge.get_results()\n", + "\n", + " # arbitrary force components\n", + " r_mat = [[og.ops.eleForce(25)[1],[og.ops.nodeDisp(n)[1] for n in [2,9,16,23,30,37,44,51,58,65]]]]\n", + "\n", + " return r_mat" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "50e8e494-9924-413c-867e-0b7383e861a4", + "metadata": {}, + "outputs": [], + "source": [ + "simple_beam_updating = clb.ModelUpdating(\n", + " function_handle=main,\n", + " param_list=start,\n", + " target_list=target,\n", + " max_error=0.1,\n", + " write_output_txt=False\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a1f0bdc8-307c-4fad-8be8-e7a65c339363", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0.2, 0.1], [0.3365125562453617, 0.10119151305405859], [0.45716219684186105, 0.1008159604001884], [0.5002470885555945, 0.10009323201609568]]\n" + ] + } + ], + "source": [ + "simple_beam_updating.update_model()\n", + "print(simple_beam_updating.param_update_history)" + ] + }, + { + "cell_type": "markdown", + "id": "ddf76bc8-59ac-463a-bb05-c7d8ae89c612", + "metadata": {}, + "source": [ + "As can be seen the values converged to [0.5,0.1] " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml index 5538eb1..ef20fd3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,7 @@ [project] -requires-python = ">=3.8,<=3.9" +requires-python = ">=3.8,>=3.9" +name = "calabru" +dynamic = ["version"] [build-system] requires = ["wheel >= 0.31.0", From fa310bb1eab35992fbdcd9fe164c881756083648 Mon Sep 17 00:00:00 2001 From: jngan Date: Thu, 23 May 2024 18:17:28 +1000 Subject: [PATCH 3/3] refactor: improve structure and naming for docs --- calabru/__init__.py | 4 -- docs/requirement.txt | 3 +- .../_templates/custom-class-template.rst | 34 ++++++++++ .../_templates/custom-module-template.rst | 66 +++++++++++++++++++ docs/source/api.rst | 4 +- docs/source/conf.py | 3 +- docs/source/index.rst | 2 - pyproject.toml | 6 ++ src/calabru/__init__.py | 8 +++ {calabru => src/calabru}/calibrator.py | 6 +- calabru/helpers.py => src/calabru/utils.py | 6 ++ tests/test_updating.py | 20 +++--- 12 files changed, 140 insertions(+), 22 deletions(-) delete mode 100644 calabru/__init__.py create mode 100644 docs/source/_templates/custom-class-template.rst create mode 100644 docs/source/_templates/custom-module-template.rst create mode 100644 src/calabru/__init__.py rename {calabru => src/calabru}/calibrator.py (99%) rename calabru/helpers.py => src/calabru/utils.py (98%) diff --git a/calabru/__init__.py b/calabru/__init__.py deleted file mode 100644 index 50ec9eb..0000000 --- a/calabru/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -__version__ = "0.1.0" - -from .calibrator import * -from .helpers import * diff --git a/docs/requirement.txt b/docs/requirement.txt index 431240c..d380880 100644 --- a/docs/requirement.txt +++ b/docs/requirement.txt @@ -11,4 +11,5 @@ pandoc markupsafe==2.0.1 pygments >= 2.7 pycba -ospgrillage \ No newline at end of file +ospgrillage +ipython \ No newline at end of file diff --git a/docs/source/_templates/custom-class-template.rst b/docs/source/_templates/custom-class-template.rst new file mode 100644 index 0000000..f73eda5 --- /dev/null +++ b/docs/source/_templates/custom-class-template.rst @@ -0,0 +1,34 @@ +{{ fullname | escape | underline}} + +.. currentmodule:: {{ module }} + +.. autoclass:: {{ objname }} + :members: + :show-inheritance: + :inherited-members: + :special-members: __call__, __add__, __mul__ + + {% block methods %} + {% if methods %} + .. rubric:: {{ _('Methods') }} + + .. autosummary:: + :nosignatures: + {% for item in methods %} + {%- if not item.startswith('_') %} + ~{{ name }}.{{ item }} + {%- endif -%} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block attributes %} + {% if attributes %} + .. rubric:: {{ _('Attributes') }} + + .. autosummary:: + {% for item in attributes %} + ~{{ name }}.{{ item }} + {%- endfor %} + {% endif %} + {% endblock %} diff --git a/docs/source/_templates/custom-module-template.rst b/docs/source/_templates/custom-module-template.rst new file mode 100644 index 0000000..d066d0e --- /dev/null +++ b/docs/source/_templates/custom-module-template.rst @@ -0,0 +1,66 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + + {% block attributes %} + {% if attributes %} + .. rubric:: Module attributes + + .. autosummary:: + :toctree: + {% for item in attributes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block functions %} + {% if functions %} + .. rubric:: {{ _('Functions') }} + + .. autosummary:: + :toctree: + :nosignatures: + {% for item in functions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block classes %} + {% if classes %} + .. rubric:: {{ _('Classes') }} + + .. autosummary:: + :toctree: + :template: custom-class-template.rst + :nosignatures: + {% for item in classes %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + + {% block exceptions %} + {% if exceptions %} + .. rubric:: {{ _('Exceptions') }} + + .. autosummary:: + :toctree: + {% for item in exceptions %} + {{ item }} + {%- endfor %} + {% endif %} + {% endblock %} + +{% block modules %} +{% if modules %} +.. autosummary:: + :toctree: + :template: custom-module-template.rst + :recursive: +{% for item in modules %} + {{ item }} +{%- endfor %} +{% endif %} +{% endblock %} diff --git a/docs/source/api.rst b/docs/source/api.rst index 395856e..1982144 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -6,8 +6,10 @@ Package Modules .. autosummary:: :toctree: gen + :template: custom-module-template.rst :recursive: calabru.calibrator - calabru.helpers + calabru.utils + diff --git a/docs/source/conf.py b/docs/source/conf.py index 0fa483c..b7dc920 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,7 +13,8 @@ import os import sys -sys.path.insert(0, os.path.abspath("../../calabru/")) +sys.path.insert(0, os.path.abspath("../../src/.")) +sys.path.insert(0, os.path.abspath("../../src/calabru/")) from calabru import __version__ as ver # diff --git a/docs/source/index.rst b/docs/source/index.rst index f72c43b..ce249c6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,8 +17,6 @@ Welcome to calabru's documentation! installation api - notebooks/intro - notebooks/example diff --git a/pyproject.toml b/pyproject.toml index ef20fd3..42f0fa8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,12 @@ requires = ["wheel >= 0.31.0", ] build-backend = "setuptools.build_meta" +[project.optional-dependencies] +test = ["pytest >= 6.2.2"] + +[tool.setuptools.dynamic] +version = {attr = "calabru.__version__"} + [tool.pytest.ini_options] minversion = "6.0" testpaths = [ diff --git a/src/calabru/__init__.py b/src/calabru/__init__.py new file mode 100644 index 0000000..3d11a85 --- /dev/null +++ b/src/calabru/__init__.py @@ -0,0 +1,8 @@ +""" +calabru - Calibration of models in Python +""" + +__version__ = "0.1.0" + +from .calibrator import * +from .utils import * \ No newline at end of file diff --git a/calabru/calibrator.py b/src/calabru/calibrator.py similarity index 99% rename from calabru/calibrator.py rename to src/calabru/calibrator.py index e41e440..c676d5e 100644 --- a/calabru/calibrator.py +++ b/src/calabru/calibrator.py @@ -5,16 +5,18 @@ from datetime import datetime import copy -from helpers import * +import numpy as np +from utils import get_pseudo_inv_estimation,interpolate_measurements,calculate_rmse -class ModelUpdating: +class Calibrator: """ Main class to handle updating. """ def __init__(self, function_handle, **kwargs): """ + Init the class Parameters ---------- diff --git a/calabru/helpers.py b/src/calabru/utils.py similarity index 98% rename from calabru/helpers.py rename to src/calabru/utils.py index 0a83b2c..4a054f3 100644 --- a/calabru/helpers.py +++ b/src/calabru/utils.py @@ -1,3 +1,8 @@ +# -*- coding: utf-8 -*- +""" +Utility function module +""" + import numpy as np from scipy.interpolate import interp1d def get_pseudo_inv_estimation(sens_mat, resp_diff): @@ -43,6 +48,7 @@ def get_pseudo_inv_estimation(sens_mat, resp_diff): def calculate_rmse(ref_response_list, current_response_list): """Get the root mean square error (RMSE) between the reference and current response values + Parameters ---------- ref_response_list: list diff --git a/tests/test_updating.py b/tests/test_updating.py index 1c67a4e..7bdb106 100644 --- a/tests/test_updating.py +++ b/tests/test_updating.py @@ -1,12 +1,10 @@ """ Main module for model calibration """ -import pytest import sys, os -import numpy as np -sys.path.insert(0, os.path.abspath("../")) -from calabru.calibrator import * +sys.path.insert(0, os.path.abspath("../src/calabru")) +from calabru import * import fixtures @@ -18,7 +16,7 @@ def test_basic_update(): """ start = [2000, 0.2] target = [1558.6480741602825, 2956.470189168508] # [-30785, -3801] - simple_beam_updating = ModelUpdating( + simple_beam_updating = Calibrator( function_handle=fixtures.beam_with_patch_load, param_list=start, target_list=target, @@ -51,7 +49,7 @@ def test_main(): 0.0]]] # node displacements - simple_beam_updating = ModelUpdating( + simple_beam_updating = Calibrator( function_handle=fixtures.main, param_list=start, target_list=target, @@ -83,7 +81,7 @@ def test_target_resp_as_list(): 0.0, ] ] # [-30785, -3801] - simple_beam_updating = ModelUpdating( + simple_beam_updating = Calibrator( function_handle=fixtures.beam_with_patch_load_including_deflected_shape_output, param_list=start, target_list=target, @@ -109,7 +107,7 @@ def test_param_bounds(): # bounds set to first param bounds = [[1500, 3000], []] target = [1558.6480741602825, 2956.470189168508] # [-30785, -3801] - simple_beam_updating = ModelUpdating( + simple_beam_updating = Calibrator( function_handle=fixtures.beam_with_patch_load, param_list=start, target_list=target, @@ -145,7 +143,7 @@ def test_robust(): """ start = [10] # P magnitude of UDL in span 1 target = [65.42524] - pycba_updating = ModelUpdating( + pycba_updating = Calibrator( function_handle=fixtures.pycba_example, param_list=start, target_list=target ) pycba_updating.update_model() @@ -170,7 +168,7 @@ def test_static_truck_pycba(): -149.1317283092082 + np.random.rand(1)[0], -96.10790029773669 + np.random.rand(1)[0], ] - pycba_updating = ModelUpdating( + pycba_updating = Calibrator( function_handle=fixtures.pycba_example_find_ei, param_list=start_ei, target_list=target_def, @@ -306,7 +304,7 @@ def test_moving_truck_pycba(): known_measurement_with_noise = [a + np.random.rand(1)[0] for a in known_measurement] known_target_ei = 100 - pycba_updating = ModelUpdating( + pycba_updating = Calibrator( function_handle=fixtures.pycba_example_moving_veh_ei, param_list=start_ei, target_list=[known_measurement_with_noise],