From 981cb5f821db2571cb42148a9c2c8b5cd47bc61a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 18 Oct 2020 19:33:32 +0300 Subject: [PATCH] Migrate to git. Update versions --- .gitignore | 5 + .hgignore | 13 - build.gradle | 9 +- gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 10 +- gradlew | 53 +- gradlew.bat | 43 +- .../inr/mass}/trapping/FunctionCache.kt | 44 +- .../inr/mass}/trapping/MultiCounter.kt | 192 +- .../mass}/trapping/RandomGeneratorBridge.kt | 54 +- .../inr/mass}/trapping/Scatter.kt | 1965 ++++++++--------- .../inr/mass}/trapping/SimulationManager.kt | 394 ++-- .../inr/mass}/trapping/Simulator.kt | 872 ++++---- .../inr/mass}/trapping/Trapping.kt | 66 +- 14 files changed, 1865 insertions(+), 1855 deletions(-) create mode 100644 .gitignore delete mode 100644 .hgignore rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/FunctionCache.kt (63%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/MultiCounter.kt (93%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/RandomGeneratorBridge.kt (85%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/Scatter.kt (97%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/SimulationManager.kt (96%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/Simulator.kt (97%) rename src/main/kotlin/{inr/numass => ru/inr/mass}/trapping/Trapping.kt (91%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bebd19 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.gradle/ +/.idea/ +/build/ +/output/ +!gradle-wrapper.jar diff --git a/.hgignore b/.hgignore deleted file mode 100644 index 2300bba..0000000 --- a/.hgignore +++ /dev/null @@ -1,13 +0,0 @@ - -\.orig$ -\.orig\..*$ -\.chg\..*$ -\.rej$ -\.conflict\~$ -.gradle/ -output/ -.ipynb_checkpoints/ -notebooks/images/ -build/ -.idea/* -!gradle-wrapper.jar diff --git a/build.gradle b/build.gradle index d464d5c..9b36dbc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,14 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "1.3.10" - id "java" + id "org.jetbrains.kotlin.jvm" version "1.4.10" id "application" } -group = 'inr.numass' -version = 'dev' +group = 'ru.inr.mass' +version = '1.0.0' description = "Numass trapping simulation" -mainClassName = "inr.numass.trapping.TrappingKt" +mainClassName = "ru.inr.mass.trapping.TrappingKt" repositories { mavenCentral() diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a5fe1cb94b9ee5ce57e6113458225bcba12d83e3..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch literal 59203 zcma&O1CT9Y(k9%tZQHhO+qUh#ZQHhO+qmuS+qP|E@9xZO?0h@l{(r>DQ>P;GjjD{w zH}lENr;dU&FbEU?00aa80D$0M0RRB{U*7-#kbjS|qAG&4l5%47zyJ#WrfA#1$1Ctx zf&Z_d{GW=lf^w2#qRJ|CvSJUi(^E3iv~=^Z(zH}F)3Z%V3`@+rNB7gTVU{Bb~90p|f+0(v;nz01EG7yDMX9@S~__vVgv%rS$+?IH+oZ03D5zYrv|^ zC1J)SruYHmCki$jLBlTaE5&dFG9-kq3!^i>^UQL`%gn6)jz54$WDmeYdsBE9;PqZ_ zoGd=P4+|(-u4U1dbAVQrFWoNgNd;0nrghPFbQrJctO>nwDdI`Q^i0XJDUYm|T|RWc zZ3^Qgo_Qk$%Fvjj-G}1NB#ZJqIkh;kX%V{THPqOyiq)d)0+(r9o(qKlSp*hmK#iIY zA^)Vr$-Hz<#SF=0@tL@;dCQsm`V9s1vYNq}K1B)!XSK?=I1)tX+bUV52$YQu*0%fnWEukW>mxkz+%3-S!oguE8u#MGzST8_Dy^#U?fA@S#K$S@9msUiX!gd_ow>08w5)nX{-KxqMOo7d?k2&?Vf z&diGDtZr(0cwPe9z9FAUSD9KC)7(n^lMWuayCfxzy8EZsns%OEblHFSzP=cL6}?J| z0U$H!4S_TVjj<`6dy^2j`V`)mC;cB%* z8{>_%E1^FH!*{>4a7*C1v>~1*@TMcLK{7nEQ!_igZC}ikJ$*<$yHy>7)oy79A~#xE zWavoJOIOC$5b6*q*F_qN1>2#MY)AXVyr$6x4b=$x^*aqF*L?vmj>Mgv+|ITnw_BoW zO?jwHvNy^prH{9$rrik1#fhyU^MpFqF2fYEt(;4`Q&XWOGDH8k6M=%@fics4ajI;st# zCU^r1CK&|jzUhRMv;+W~6N;u<;#DI6cCw-otsc@IsN3MoSD^O`eNflIoR~l4*&-%RBYk@gb^|-JXs&~KuSEmMxB}xSb z@K76cXD=Y|=I&SNC2E+>Zg?R6E%DGCH5J1nU!A|@eX9oS(WPaMm==k2s_ueCqdZw| z&hqHp)47`c{BgwgvY2{xz%OIkY1xDwkw!<0veB#yF4ZKJyabhyyVS`gZepcFIk%e2 zTcrmt2@-8`7i-@5Nz>oQWFuMC_KlroCl(PLSodswHqJ3fn<;gxg9=}~3x_L3P`9Sn zChIf}8vCHvTriz~T2~FamRi?rh?>3bX1j}%bLH+uFX+p&+^aXbOK7clZxdU~6Uxgy z8R=obwO4dL%pmVo*Ktf=lH6hnlz_5k3cG;m8lgaPp~?eD!Yn2kf)tU6PF{kLyn|oI@eQ`F z3IF7~Blqg8-uwUuWZScRKn%c2_}dXB6Dx_&xR*n9M9LXasJhtZdr$vBY!rP{c@=)& z#!?L$2UrkvClwQO>U*fSMs67oSj2mxiJ$t;E|>q%Kh_GzzWWO&3;ufU%2z%ucBU8H z3WIwr$n)cfCXR&>tyB7BcSInK>=ByZA%;cVEJhcg<#6N{aZC4>K41XF>ZgjG`z_u& zGY?;Ad?-sgiOnI`oppF1o1Gurqbi*;#x2>+SSV6|1^G@ooVy@fg?wyf@0Y!UZ4!}nGuLeC^l)6pwkh|oRY`s1Pm$>zZ3u-83T|9 zGaKJIV3_x+u1>cRibsaJpJqhcm%?0-L;2 zitBrdRxNmb0OO2J%Y&Ym(6*`_P3&&5Bw157{o7LFguvxC$4&zTy#U=W*l&(Q2MNO} zfaUwYm{XtILD$3864IA_nn34oVa_g^FRuHL5wdUd)+W-p-iWCKe8m_cMHk+=? zeKX)M?Dt(|{r5t7IenkAXo%&EXIb-i^w+0CX0D=xApC=|Xy(`xy+QG^UyFe z+#J6h_&T5i#sV)hj3D4WN%z;2+jJcZxcI3*CHXGmOF3^)JD5j&wfX)e?-|V0GPuA+ zQFot%aEqGNJJHn$!_}#PaAvQ^{3-Ye7b}rWwrUmX53(|~i0v{}G_sI9uDch_brX&6 zWl5Ndj-AYg(W9CGfQf<6!YmY>Ey)+uYd_JNXH=>|`OH-CDCmcH(0%iD_aLlNHKH z7bcW-^5+QV$jK?R*)wZ>r9t}loM@XN&M-Pw=F#xn(;u3!(3SXXY^@=aoj70;_=QE9 zGghsG3ekq#N||u{4We_25U=y#T*S{4I{++Ku)> zQ!DZW;pVcn>b;&g2;YE#+V`v*Bl&Y-i@X6D*OpNA{G@JAXho&aOk(_j^weW{#3X5Y z%$q_wpb07EYPdmyH(1^09i$ca{O<}7) zRWncXdSPgBE%BM#by!E>tdnc$8RwUJg1*x($6$}ae$e9Knj8gvVZe#bLi!<+&BkFj zg@nOpDneyc+hU9P-;jmOSMN|*H#>^Ez#?;%C3hg_65leSUm;iz)UkW)jX#p)e&S&M z1|a?wDzV5NVnlhRBCd_;F87wp>6c<&nkgvC+!@KGiIqWY4l}=&1w7|r6{oBN8xyzh zG$b#2=RJp_iq6)#t5%yLkKx(0@D=C3w+oiXtSuaQ%I1WIb-eiE$d~!)b@|4XLy!CZ z9p=t=%3ad@Ep+<9003D2KZ5VyP~_n$=;~r&YUg5UZ0KVD&tR1DHy9x)qWtKJp#Kq# zP*8p#W(8JJ_*h_3W}FlvRam?<4Z+-H77^$Lvi+#vmhL9J zJ<1SV45xi;SrO2f=-OB(7#iNA5)x1uNC-yNxUw|!00vcW2PufRm>e~toH;M0Q85MQLWd?3O{i8H+5VkR@l9Dg-ma ze2fZ%>G(u5(k9EHj2L6!;(KZ8%8|*-1V|B#EagbF(rc+5iL_5;Eu)L4Z-V;0HfK4d z*{utLse_rvHZeQ>V5H=f78M3Ntg1BPxFCVD{HbNA6?9*^YIq;B-DJd{Ca2L#)qWP? zvX^NhFmX?CTWw&Ns}lgs;r3i+Bq@y}Ul+U%pzOS0Fcv9~aB(0!>GT0)NO?p=25LjN z2bh>6RhgqD7bQj#k-KOm@JLgMa6>%-ok1WpOe)FS^XOU{c?d5shG(lIn3GiVBxmg`u%-j=)^v&pX1JecJics3&jvPI)mDut52? z3jEA)DM%}BYbxxKrizVYwq?(P&19EXlwD9^-6J+4!}9{ywR9Gk42jjAURAF&EO|~N z)?s>$Da@ikI4|^z0e{r`J8zIs>SpM~Vn^{3fArRu;?+43>lD+^XtUcY1HidJwnR6+ z!;oG2=B6Z_=M%*{z-RaHc(n|1RTKQdNjjV!Pn9lFt^4w|AeN06*j}ZyhqZ^!-=cyGP_ShV1rGxkx8t zB;8`h!S{LD%ot``700d0@Grql(DTt4Awgmi+Yr0@#jbe=2#UkK%rv=OLqF)9D7D1j z!~McAwMYkeaL$~kI~90)5vBhBzWYc3Cj1WI0RS`z000R8-@ET0dA~*r(gSiCJmQMN&4%1D zyVNf0?}sBH8zNbBLn>~(W{d3%@kL_eQ6jEcR{l>C|JK z(R-fA!z|TTRG40|zv}7E@PqCAXP3n`;%|SCQ|ZS%ym$I{`}t3KPL&^l5`3>yah4*6 zifO#{VNz3)?ZL$be;NEaAk9b#{tV?V7 zP|wf5YA*1;s<)9A4~l3BHzG&HH`1xNr#%){4xZ!jq%o=7nN*wMuXlFV{HaiQLJ`5G zBhDi#D(m`Q1pLh@Tq+L;OwuC52RdW7b8}~60WCOK5iYMUad9}7aWBuILb({5=z~YF zt?*Jr5NG+WadM{mDL>GyiByCuR)hd zA=HM?J6l1Xv0Dl+LW@w$OTcEoOda^nFCw*Sy^I@$sSuneMl{4ys)|RY#9&NxW4S)9 zq|%83IpslTLoz~&vTo!Ga@?rj_kw{|k{nv+w&Ku?fyk4Ki4I?);M|5Axm)t+BaE)D zm(`AQ#k^DWrjbuXoJf2{Aj^KT zFb1zMSqxq|vceV+Mf-)$oPflsO$@*A0n0Z!R{&(xh8s}=;t(lIy zv$S8x>m;vQNHuRzoaOo?eiWFe{0;$s`Bc+Osz~}Van${u;g(su`3lJ^TEfo~nERfP z)?aFzpDgnLYiERsKPu|0tq4l2wT)Atr6Qb%m-AUn6HnCue*yWICp7TjW$@sO zm5rm4aTcPQ(rfi7a`xP7cKCFrJD}*&_~xgLyr^-bmsL}y;A5P|al8J3WUoBSjqu%v zxC;mK!g(7r6RRJ852Z~feoC&sD3(6}^5-uLK8o)9{8L_%%rItZK9C){UxB|;G>JbP zsRRtS4-3B*5c+K2kvmgZK8472%l>3cntWUOVHxB|{Ay~aOg5RN;{PJgeVD*H%ac+y!h#wi%o2bF2Ca8IyMyH{>4#{E_8u^@+l-+n=V}Sq?$O z{091@v%Bd*3pk0^2UtiF9Z+(a@wy6 zUdw8J*ze$K#=$48IBi1U%;hmhO>lu!uU;+RS}p&6@rQila7WftH->*A4=5W|Fmtze z)7E}jh@cbmr9iup^i%*(uF%LG&!+Fyl@LFA-}Ca#bxRfDJAiR2dt6644TaYw1Ma79 zt8&DYj31j^5WPNf5P&{)J?WlCe@<3u^78wnd(Ja4^a>{^Tw}W>|Cjt^If|7l^l)^Q zbz|7~CF(k_9~n|h;ysZ+jHzkXf(*O*@5m zLzUmbHp=x!Q|!9NVXyipZ3)^GuIG$k;D)EK!a5=8MFLI_lpf`HPKl=-Ww%z8H_0$j ztJ||IfFG1lE9nmQ0+jPQy zCBdKkjArH@K7jVcMNz);Q(Q^R{d5G?-kk;Uu_IXSyWB)~KGIizZL(^&qF;|1PI7!E zTP`%l)gpX|OFn&)M%txpQ2F!hdA~hX1Cm5)IrdljqzRg!f{mN%G~H1&oqe`5eJCIF zHdD7O;AX-{XEV(a`gBFJ9ews#CVS2y!&>Cm_dm3C8*n3MA*e67(WC?uP@8TXuMroq z{#w$%z@CBIkRM7?}Xib+>hRjy?%G!fiw8! z8(gB+8J~KOU}yO7UGm&1g_MDJ$IXS!`+*b*QW2x)9>K~Y*E&bYMnjl6h!{17_8d!%&9D`a7r&LKZjC<&XOvTRaKJ1 zUY@hl5^R&kZl3lU3njk`3dPzxj$2foOL26r(9zsVF3n_F#v)s5vv3@dgs|lP#eylq62{<-vczqP!RpVBTgI>@O6&sU>W|do17+#OzQ7o5A$ICH z?GqwqnK^n2%LR;$^oZM;)+>$X3s2n}2jZ7CdWIW0lnGK-b#EG01)P@aU`pg}th&J-TrU`tIpb5t((0eu|!u zQz+3ZiOQ^?RxxK4;zs=l8q!-n7X{@jSwK(iqNFiRColuEOg}!7cyZi`iBX4g1pNBj zAPzL?P^Ljhn;1$r8?bc=#n|Ed7wB&oHcw()&*k#SS#h}jO?ZB246EGItsz*;^&tzp zu^YJ0=lwsi`eP_pU8}6JA7MS;9pfD;DsSsLo~ogzMNP70@@;Fm8f0^;>$Z>~}GWRw!W5J3tNX*^2+1f3hz{~rIzJo z6W%J(H!g-eI_J1>0juX$X4Cl6i+3wbc~k146UIX&G22}WE>0ga#WLsn9tY(&29zBvH1$`iWtTe zG2jYl@P!P)eb<5DsR72BdI7-zP&cZNI{7q3e@?N8IKc4DE#UVr->|-ryuJXk^u^>4 z$3wE~=q390;XuOQP~TNoDR?#|NSPJ%sTMInA6*rJ%go|=YjGe!B>z6u$IhgQSwoV* zjy3F2#I>uK{42{&IqP59)Y(1*Z>>#W8rCf4_eVsH)`v!P#^;BgzKDR`ARGEZzkNX+ zJUQu=*-ol=Xqqt5=`=pA@BIn@6a9G8C{c&`i^(i+BxQO9?YZ3iu%$$da&Kb?2kCCo zo7t$UpSFWqmydXf@l3bVJ=%K?SSw)|?srhJ-1ZdFu*5QhL$~-IQS!K1s@XzAtv6*Y zl8@(5BlWYLt1yAWy?rMD&bwze8bC3-GfNH=p zynNFCdxyX?K&G(ZZ)afguQ2|r;XoV^=^(;Cku#qYn4Lus`UeKt6rAlFo_rU`|Rq z&G?~iWMBio<78of-2X(ZYHx~=U0Vz4btyXkctMKdc9UM!vYr~B-(>)(Hc|D zMzkN4!PBg%tZoh+=Gba!0++d193gbMk2&krfDgcbx0jI92cq?FFESVg0D$>F+bil} zY~$)|>1HZsX=5sAZ2WgPB5P=8X#TI+NQ(M~GqyVB53c6IdX=k>Wu@A0Svf5#?uHaF zsYn|koIi3$(%GZ2+G+7Fv^lHTb#5b8sAHSTnL^qWZLM<(1|9|QFw9pnRU{svj}_Al zL)b9>fN{QiA($8peNEJyy`(a{&uh-T4_kdZFIVsKKVM(?05}76EEz?#W za^fiZOAd14IJ4zLX-n7Lq0qlQ^lW8Cvz4UKkV9~P}>sq0?xD3vg+$4vLm~C(+ zM{-3Z#qnZ09bJ>}j?6ry^h+@PfaD7*jZxBEY4)UG&daWb??6)TP+|3#Z&?GL?1i+280CFsE|vIXQbm| zM}Pk!U`U5NsNbyKzkrul-DzwB{X?n3E6?TUHr{M&+R*2%yOiXdW-_2Yd6?38M9Vy^ z*lE%gA{wwoSR~vN0=no}tP2Ul5Gk5M(Xq`$nw#ndFk`tcpd5A=Idue`XZ!FS>Q zG^0w#>P4pPG+*NC9gLP4x2m=cKP}YuS!l^?sHSFftZy{4CoQrb_ z^20(NnG`wAhMI=eq)SsIE~&Gp9Ne0nD4%Xiu|0Fj1UFk?6avDqjdXz{O1nKao*46y zT8~iA%Exu=G#{x=KD;_C&M+Zx4+n`sHT>^>=-1YM;H<72k>$py1?F3#T1*ef9mLZw z5naLQr?n7K;2l+{_uIw*_1nsTn~I|kkCgrn;|G~##hM;9l7Jy$yJfmk+&}W@JeKcF zx@@Woiz8qdi|D%aH3XTx5*wDlbs?dC1_nrFpm^QbG@wM=i2?Zg;$VK!c^Dp8<}BTI zyRhAq@#%2pGV49*Y5_mV4+OICP|%I(dQ7x=6Ob}>EjnB_-_18*xrY?b%-yEDT(wrO z9RY2QT0`_OpGfMObKHV;QLVnrK%mc?$WAdIT`kJQT^n%GuzE7|9@k3ci5fYOh(287 zuIbg!GB3xLg$YN=n)^pHGB0jH+_iIiC=nUcD;G6LuJsjn2VI1cyZx=a?ShCsF==QK z;q~*m&}L<-cb+mDDXzvvrRsybcgQ;Vg21P(uLv5I+eGc7o7tc6`;OA9{soHFOz zT~2?>Ts}gprIX$wRBb4yE>ot<8+*Bv`qbSDv*VtRi|cyWS>)Fjs>fkNOH-+PX&4(~ z&)T8Zam2L6puQl?;5zg9h<}k4#|yH9czHw;1jw-pwBM*O2hUR6yvHATrI%^mvs9q_ z&ccT0>f#eDG<^WG^q@oVqlJrhxH)dcq2cty@l3~|5#UDdExyXUmLQ}f4#;6fI{f^t zDCsgIJ~0`af%YR%Ma5VQq-p21k`vaBu6WE?66+5=XUd%Ay%D$irN>5LhluRWt7 zov-=f>QbMk*G##&DTQyou$s7UqjjW@k6=!I@!k+S{pP8R(2=e@io;N8E`EOB;OGoI zw6Q+{X1_I{OO0HPpBz!X!@`5YQ2)t{+!?M_iH25X(d~-Zx~cXnS9z>u?+If|iNJbx zyFU2d1!ITX64D|lE0Z{dLRqL1Ajj=CCMfC4lD3&mYR_R_VZ>_7_~|<^o*%_&jevU+ zQ4|qzci=0}Jydw|LXLCrOl1_P6Xf@c0$ieK2^7@A9UbF{@V_0p%lqW|L?5k>bVM8|p5v&2g;~r>B8uo<4N+`B zH{J)h;SYiIVx@#jI&p-v3dwL5QNV1oxPr8J%ooezTnLW>i*3Isb49%5i!&ac_dEXv zvXmVUck^QHmyrF8>CGXijC_R-y(Qr{3Zt~EmW)-nC!tiH`wlw5D*W7Pip;T?&j%kX z6DkZX4&}iw>hE(boLyjOoupf6JpvBG8}jIh!!VhnD0>}KSMMo{1#uU6kiFcA04~|7 zVO8eI&x1`g4CZ<2cYUI(n#wz2MtVFHx47yE5eL~8bot~>EHbevSt}LLMQX?odD{Ux zJMnam{d)W4da{l7&y-JrgiU~qY3$~}_F#G7|MxT)e;G{U`In&?`j<5D->}cb{}{T(4DF0BOk-=1195KB-E*o@c?`>y#4=dMtYtSY=&L{!TAjFVcq0y@AH`vH! z$41+u!Ld&}F^COPgL(EE{0X7LY&%D7-(?!kjFF7=qw<;`V{nwWBq<)1QiGJgUc^Vz ztMUlq1bZqKn17|6x6iAHbWc~l1HcmAxr%$Puv!znW)!JiukwIrqQ00|H$Z)OmGG@= zv%A8*4cq}(?qn4rN6o`$Y))(MyXr8R<2S^J+v(wmFmtac!%VOfN?&(8Nr!T@kV`N; z*Q33V3t`^rN&aBiHet)18wy{*wi1=W!B%B-Q6}SCrUl$~Hl{@!95ydml@FK8P=u4s z4e*7gV2s=YxEvskw2Ju!2%{8h01rx-3`NCPc(O zH&J0VH5etNB2KY6k4R@2Wvl^Ck$MoR3=)|SEclT2ccJ!RI9Nuter7u9@;sWf-%um;GfI!=eEIQ2l2p_YWUd{|6EG ze{yO6;lMc>;2tPrsNdi@&1K6(1;|$xe8vLgiouj%QD%gYk`4p{Ktv9|j+!OF-P?@p z;}SV|oIK)iwlBs+`ROXkhd&NK zzo__r!B>tOXpBJMDcv!Mq54P+n4(@dijL^EpO1wdg~q+!DT3lB<>9AANSe!T1XgC=J^)IP0XEZ()_vpu!!3HQyJhwh?r`Ae%Yr~b% zO*NY9t9#qWa@GCPYOF9aron7thfWT`eujS4`t2uG6)~JRTI;f(ZuoRQwjZjp5Pg34 z)rp$)Kr?R+KdJ;IO;pM{$6|2y=k_siqvp%)2||cHTe|b5Ht8&A{wazGNca zX$Ol?H)E_R@SDi~4{d-|8nGFhZPW;Cts1;08TwUvLLv&_2$O6Vt=M)X;g%HUr$&06 zISZb(6)Q3%?;3r~*3~USIg=HcJhFtHhIV(siOwV&QkQe#J%H9&E21!C*d@ln3E@J* zVqRO^<)V^ky-R|%{(9`l-(JXq9J)1r$`uQ8a}$vr9E^nNiI*thK8=&UZ0dsFN_eSl z(q~lnD?EymWLsNa3|1{CRPW60>DSkY9YQ;$4o3W7Ms&@&lv9eH!tk~N&dhqX&>K@} zi1g~GqglxkZ5pEFkllJ)Ta1I^c&Bt6#r(QLQ02yHTaJB~- zCcE=5tmi`UA>@P=1LBfBiqk)HB4t8D?02;9eXj~kVPwv?m{5&!&TFYhu>3=_ zsGmYZ^mo*-j69-42y&Jj0cBLLEulNRZ9vXE)8~mt9C#;tZs;=#M=1*hebkS;7(aGf zcs7zH(I8Eui9UU4L--))yy`&d&$In&VA2?DAEss4LAPCLd>-$i?lpXvn!gu^JJ$(DoUlc6wE98VLZ*z`QGQov5l4Fm_h?V-;mHLYDVOwKz7>e4+%AzeO>P6v}ndPW| zM>m#6Tnp7K?0mbK=>gV}=@k*0Mr_PVAgGMu$j+pWxzq4MAa&jpCDU&-5eH27Iz>m^ zax1?*HhG%pJ((tkR(V(O(L%7v7L%!_X->IjS3H5kuXQT2!ow(;%FDE>16&3r){!ex zhf==oJ!}YU89C9@mfDq!P3S4yx$aGB?rbtVH?sHpg?J5C->!_FHM%Hl3#D4eplxzQ zRA+<@LD%LKSkTk2NyWCg7u=$%F#;SIL44~S_OGR}JqX}X+=bc@swpiClB`Zbz|f!4 z7Ysah7OkR8liXfI`}IIwtEoL}(URrGe;IM8%{>b1SsqXh)~w}P>yiFRaE>}rEnNkT z!HXZUtxUp1NmFm)Dm@-{FI^aRQqpSkz}ZSyKR%Y}YHNzBk)ZIp} zMtS=aMvkgWKm9&oTcU0?S|L~CDqA+sHpOxwnswF-fEG)cXCzUR?ps@tZa$=O)=L+5 zf%m58cq8g_o}3?Bhh+c!w4(7AjxwQ3>WnVi<{{38g7yFboo>q|+7qs<$8CPXUFAN< zG&}BHbbyQ5n|qqSr?U~GY{@GJ{(Jny{bMaOG{|IkUj7tj^9pa9|FB_<+KHLxSxR;@ zHpS$4V)PP+tx}22fWx(Ku9y+}Ap;VZqD0AZW4gCDTPCG=zgJmF{|x;(rvdM|2|9a}cex6xrMkERnkE;}jvU-kmzd%_J50$M`lIPCKf+^*zL=@LW`1SaEc%=m zQ+lT06Gw+wVwvQ9fZ~#qd430v2HndFsBa9WjD0P}K(rZYdAt^5WQIvb%D^Q|pkVE^ zte$&#~zmULFACGfS#g=2OLOnIf2Of-k!(BIHjs77nr!5Q1*I9 z1%?=~#Oss!rV~?-6Gm~BWJiA4mJ5TY&iPm_$)H1_rTltuU1F3I(qTQ^U$S>%$l z)Wx1}R?ij0idp@8w-p!Oz{&*W;v*IA;JFHA9%nUvVDy7Q8woheC#|8QuDZb-L_5@R zOqHwrh|mVL9b=+$nJxM`3eE{O$sCt$UK^2@L$R(r^-_+z?lOo+me-VW=Zw z-Bn>$4ovfWd%SPY`ab-u9{INc*k2h+yH%toDHIyqQ zO68=u`N}RIIs7lsn1D){)~%>ByF<>i@qFb<-axvu(Z+6t7v<^z&gm9McRB~BIaDn$ z#xSGT!rzgad8o>~kyj#h1?7g96tOcCJniQ+*#=b7wPio>|6a1Z?_(TS{)KrPe}(8j z!#&A=k(&Pj^F;r)CI=Z{LVu>uj!_W1q4b`N1}E(i%;BWjbEcnD=mv$FL$l?zS6bW!{$7j1GR5ocn94P2u{ z70tAAcpqtQo<@cXw~@i-@6B23;317|l~S>CB?hR5qJ%J3EFgyBdJd^fHZu7AzHF(BQ!tyAz^L0`X z23S4Fe{2X$W0$zu9gm%rg~A>ijaE#GlYlrF9$ds^QtaszE#4M(OLVP2O-;XdT(XIC zatwzF*)1c+t~c{L=fMG8Z=k5lv>U0;C{caN1NItnuSMp)6G3mbahu>E#sj&oy94KC zpH}8oEw{G@N3pvHhp{^-YaZeH;K+T_1AUv;IKD<=mv^&Ueegrb!yf`4VlRl$M?wsl zZyFol(2|_QM`e_2lYSABpKR{{NlxlDSYQNkS;J66aT#MSiTx~;tUmvs-b*CrR4w=f z8+0;*th6kfZ3|5!Icx3RV11sp=?`0Jy3Fs0N4GZQMN=8HmT6%x9@{Dza)k}UwL6JT zHRDh;%!XwXr6yuuy`4;Xsn0zlR$k%r%9abS1;_v?`HX_hI|+EibVnlyE@3aL5vhQq zlIG?tN^w@0(v9M*&L+{_+RQZw=o|&BRPGB>e5=ys7H`nc8nx)|-g;s7mRc7hg{GJC zAe^vCIJhajmm7C6g! zL&!WAQ~5d_5)00?w_*|*H>3$loHrvFbitw#WvLB!JASO?#5Ig5$Ys10n>e4|3d;tS zELJ0|R4n3Az(Fl3-r^QiV_C;)lQ1_CW{5bKS15U|E9?ZgLec@%kXr84>5jV2a5v=w z?pB1GPdxD$IQL4)G||B_lI+A=08MUFFR4MxfGOu07vfIm+j=z9tp~5i_6jb`tR>qV z$#`=BQ*jpCjm$F0+F)L%xRlnS%#&gro6PiRfu^l!EVan|r3y}AHJQOORGx4~ z&<)3=K-tx518DZyp%|!EqpU!+X3Et7n2AaC5(AtrkW>_57i}$eqs$rupubg0a1+WO zGHZKLN2L0D;ab%{_S1Plm|hx8R?O14*w*f&2&bB050n!R2by zw!@XOQx$SqZ5I<(Qu$V6g>o#A!JVwErWv#(Pjx=KeS0@hxr4?13zj#oWwPS(7Ro|v z>Mp@Kmxo79q|}!5qtX2-O@U&&@6s~!I&)1WQIl?lTnh6UdKT_1R640S4~f=_xoN3- zI+O)$R@RjV$F=>Ti7BlnG1-cFKCC(t|Qjm{SalS~V-tX#+2ekRhwmN zZr`8{QF6y~Z!D|{=1*2D-JUa<(1Z=;!Ei!KiRNH?o{p5o3crFF=_pX9O-YyJchr$~ zRC`+G+8kx~fD2k*ZIiiIGR<8r&M@3H?%JVOfE>)})7ScOd&?OjgAGT@WVNSCZ8N(p zuQG~76GE3%(%h1*vUXg$vH{ua0b`sQ4f0*y=u~lgyb^!#CcPJa2mkSEHGLsnO^kb$ zru5_l#nu=Y{rSMWiYx?nO{8I!gH+?wEj~UM?IrG}E|bRIBUM>UlY<`T1EHpRr36vv zBi&dG8oxS|J$!zoaq{+JpJy+O^W(nt*|#g32bd&K^w-t>!Vu9N!k9eA8r!Xc{utY> zg9aZ(D2E0gL#W0MdjwES-7~Wa8iubPrd?8-$C4BP?*wok&O8+ykOx{P=Izx+G~hM8 z*9?BYz!T8~dzcZr#ux8kS7u7r@A#DogBH8km8Ry4slyie^n|GrTbO|cLhpqgMdsjX zJ_LdmM#I&4LqqsOUIXK8gW;V0B(7^$y#h3h>J0k^WJfAMeYek%Y-Dcb_+0zPJez!GM zAmJ1u;*rK=FNM0Nf}Y!!P9c4)HIkMnq^b;JFd!S3?_Qi2G#LIQ)TF|iHl~WKK6JmK zbv7rPE6VkYr_%_BT}CK8h=?%pk@3cz(UrZ{@h40%XgThP*-Oeo`T0eq9 zA8BnWZKzCy5e&&_GEsU4*;_k}(8l_&al5K-V*BFM=O~;MgRkYsOs%9eOY6s6AtE*<7GQAR2ulC3RAJrG_P1iQK5Z~&B z&f8X<>yJV6)oDGIlS$Y*D^Rj(cszTy5c81a5IwBr`BtnC6_e`ArI8CaTX_%rx7;cn zR-0?J_LFg*?(#n~G8cXut(1nVF0Oka$A$1FGcERU<^ggx;p@CZc?3UB41RY+wLS`LWFNSs~YP zuw1@DNN3lTd|jDL7gjBsd9}wIw}4xT2+8dBQzI00m<@?c2L%>}QLfK5%r!a-iII`p zX@`VEUH)uj^$;7jVUYdADQ2k*!1O3WdfgF?OMtUXNpQ1}QINamBTKDuv19^{$`8A1 zeq%q*O0mi@(%sZU>Xdb0Ru96CFqk9-L3pzLVsMQ`Xpa~N6CR{9Rm2)A|CI21L(%GW zh&)Y$BNHa=FD+=mBw3{qTgw)j0b!Eahs!rZnpu)z!!E$*eXE~##yaXz`KE5(nQM`s zD!$vW9XH)iMxu9R>r$VlLk9oIR%HxpUiW=BK@4U)|1WNQ=mz9a z^!KkO=>GaJ!GBXm{KJj^;kh-MkUlEQ%lza`-G&}C5y1>La1sR6hT=d*NeCnuK%_LV zOXt$}iP6(YJKc9j-Fxq~*ItVUqljQ8?oaysB-EYtFQp9oxZ|5m0^Hq(qV!S+hq#g( z?|i*H2MIr^Kxgz+3vIljQ*Feejy6S4v~jKEPTF~Qhq!(ms5>NGtRgO5vfPPc4Z^AM zTj!`5xEreIN)vaNxa|q6qWdg>+T`Ol0Uz)ckXBXEGvPNEL3R8hB3=C5`@=SYgAju1 z!)UBr{2~=~xa{b8>x2@C7weRAEuatC)3pkRhT#pMPTpSbA|tan%U7NGMvzmF?c!V8 z=pEWxbdXbTAGtWTyI?Fml%lEr-^AE}w#l(<7OIw;ctw}imYax&vR4UYNJZK6P7ZOd zP87XfhnUHxCUHhM@b*NbTi#(-8|wcv%3BGNs#zRCVV(W?1Qj6^PPQa<{yaBwZ`+<`w|;rqUY_C z&AeyKwwf*q#OW-F()lir=T^<^wjK65Lif$puuU5+tk$;e_EJ;Lu+pH>=-8=PDhkBg z8cWt%@$Sc#C6F$Vd+0507;{OOyT7Hs%nKS88q-W!$f~9*WGBpHGgNp}=C*7!RiZ5s zn1L_DbKF@B8kwhDiLKRB@lsXVVLK|ph=w%_`#owlf@s@V(pa`GY$8h%;-#h@TsO|Y8V=n@*!Rog7<7Cid%apR|x zOjhHCyfbIt%+*PCveTEcuiDi%Wx;O;+K=W?OFUV%)%~6;gl?<0%)?snDDqIvkHF{ zyI02)+lI9ov42^hL>ZRrh*HhjF9B$A@=H94iaBESBF=eC_KT$8A@uB^6$~o?3Wm5t1OIaqF^~><2?4e3c&)@wKn9bD? zoeCs;H>b8DL^F&>Xw-xjZEUFFTv>JD^O#1E#)CMBaG4DX9bD(Wtc8Rzq}9soQ8`jf zeSnHOL}<+WVSKp4kkq&?SbETjq6yr@4%SAqOG=9E(3YeLG9dtV+8vmzq+6PFPk{L; z(&d++iu=^F%b+ea$i2UeTC{R*0Isk;vFK!no<;L+(`y`3&H-~VTdKROkdyowo1iqR zbVW(3`+(PQ2>TKY>N!jGmGo7oeoB8O|P_!Ic@ zZ^;3dnuXo;WJ?S+)%P>{Hcg!Jz#2SI(s&dY4QAy_vRlmOh)QHvs_7c&zkJCmJGVvV zX;Mtb>QE+xp`KyciG$Cn*0?AK%-a|=o!+7x&&yzHQOS>8=B*R=niSnta^Pxp1`=md z#;$pS$4WCT?mbiCYU?FcHGZ#)kHVJTTBt^%XE(Q};aaO=Zik0UgLcc0I(tUpt(>|& zcxB_|fxCF7>&~5eJ=Dpn&5Aj{A^cV^^}(7w#p;HG&Q)EaN~~EqrE1qKrMAc&WXIE;>@<&)5;gD2?={Xf@Mvn@OJKw=8Mgn z!JUFMwD+s==JpjhroT&d{$kQAy%+d`a*XxDEVxy3`NHzmITrE`o!;5ClXNPb4t*8P zzAivdr{j_v!=9!^?T3y?gzmqDWX6mkzhIzJ-3S{T5bcCFMr&RPDryMcdwbBuZbsgN zGrp@^i?rcfN7v0NKGzDPGE#4yszxu=I_`MI%Z|10nFjU-UjQXXA?k8Pk|OE<(?ae) zE%vG#eZAlj*E7_3dx#Zz4kMLj>H^;}33UAankJiDy5ZvEhrjr`!9eMD8COp}U*hP+ zF}KIYx@pkccIgyxFm#LNw~G&`;o&5)2`5aogs`1~7cMZQ7zj!%L4E`2yzlQN6REX20&O<9 zKV6fyr)TScJPPzNTC2gL+0x#=u>(({{D7j)c-%tvqls3#Y?Z1m zV5WUE)zdJ{$p>yX;^P!UcXP?UD~YM;IRa#Rs5~l+*$&nO(;Ers`G=0D!twR(0GF@c zHl9E5DQI}Oz74n zfKP>&$q0($T4y$6w(p=ERAFh+>n%iaeRA%!T%<^+pg?M)@ucY<&59$x9M#n+V&>}=nO9wCV{O~lg&v#+jcUj(tQ z`0u1YH)-`U$15a{pBkGyPL0THv1P|4e@pf@3IBZS4dVJPo#H>pWq%Lr0YS-SeWash z8R7=jb28KPMI|_lo#GEO|5B?N_e``H*23{~a!AmUJ+fb4HX-%QI@lSEUxKlGV7z7Q zSKw@-TR>@1RL%w{x}dW#k1NgW+q4yt2Xf1J62Bx*O^WG8OJ|FqI4&@d3_o8Id@*)4 zYrk=>@!wv~mh7YWv*bZhxqSmFh2Xq)o=m;%n$I?GSz49l1$xRpPu_^N(vZ>*>Z<04 z2+rP70oM=NDysd!@fQdM2OcyT?3T^Eb@lIC-UG=Bw{BjQ&P`KCv$AcJ;?`vdZ4){d z&gkoUK{$!$$K`3*O-jyM1~p-7T*qb)Ys>Myt^;#1&a%O@x8A+E>! zY8=eD`ZG)LVagDLBeHg>=atOG?Kr%h4B%E6m@J^C+U|y)XX@f z8oyJDW|9g=<#f<{JRr{y#~euMnv)`7j=%cHWLc}ngjq~7k**6%4u>Px&W%4D94(r* z+akunK}O0DC2A%Xo9jyF;DobX?!1I(7%}@7F>i%&nk*LMO)bMGg2N+1iqtg+r(70q zF5{Msgsm5GS7DT`kBsjMvOrkx&|EU!{{~gL4d2MWrAT=KBQ-^zQCUq{5PD1orxlIL zq;CvlWx#f1NWvh`hg011I%?T_s!e38l*lWVt|~z-PO4~~1g)SrJ|>*tXh=QfXT)%( z+ex+inPvD&O4Ur;JGz>$sUOnWdpSLcm1X%aQDw4{dB!cnj`^muI$CJ2%p&-kULVCE z>$eMR36kN$wCPR+OFDM3-U(VOrp9k3)lI&YVFqd;Kpz~K)@Fa&FRw}L(SoD z9B4a+hQzZT-BnVltst&=kq6Y(f^S4hIGNKYBgMxGJ^;2yrO}P3;r)(-I-CZ)26Y6? z&rzHI_1GCvGkgy-t1E;r^3Le30|%$ebDRu2+gdLG)r=A~Qz`}~&L@aGJ{}vVs_GE* zVUjFnzHiXfKQbpv&bR&}l2bzIjAooB)=-XNcYmrGmBh(&iu@o!^hn0^#}m2yZZUK8 zufVm7Gq0y`Mj;9b>`c?&PZkU0j4>IL=UL&-Lp3j&47B5pAW4JceG{!XCA)kT<%2nqCxj<)uy6XR_uws~>_MEKPOpAQ!H zkn>FKh)<9DwwS*|Y(q?$^N!6(51O0 z^JM~Ax{AI1Oj$fs-S5d4T7Z_i1?{%0SsIuQ&r8#(JA=2iLcTN+?>wOL532%&dMYkT z*T5xepC+V6zxhS@vNbMoi|i)=rpli@R9~P!39tWbSSb904ekv7D#quKbgFEMTb48P zuq(VJ+&L8aWU(_FCD$3^uD!YM%O^K(dvy~Wm2hUuh6bD|#(I39Xt>N1Y{ZqXL`Fg6 zKQ?T2htHN!(Bx;tV2bfTtIj7e)liN-29s1kew>v(D^@)#v;}C4-G=7x#;-dM4yRWm zyY`cS21ulzMK{PoaQ6xChEZ}o_#}X-o}<&0)$1#3we?+QeLt;aVCjeA)hn!}UaKt< zat1fHEx13y-rXNMvpUUmCVzocPmN~-Y4(YJvQ#db)4|%B!rBsgAe+*yor~}FrNH08 z3V!97S}D7d$zbSD{$z;@IYMxM6aHdypIuS*pr_U6;#Y!_?0i|&yU*@16l z*dcMqDQgfNBf}?quiu4e>H)yTVfsp#f+Du0@=Kc41QockXkCkvu>FBd6Q+@FL!(Yx z2`YuX#eMEiLEDhp+9uFqME_E^faV&~9qjBHJkIp~%$x^bN=N)K@kvSVEMdDuzA0sn z88CBG?`RX1@#hQNd`o^V{37)!w|nA)QfiYBE^m=yQKv-fQF+UCMcuEe1d4BH7$?>b zJl-r9@0^Ie=)guO1vOd=i$_4sz>y3x^R7n4ED!5oXL3@5**h(xr%Hv)_gILarO46q+MaDOF%ChaymKoI6JU5Pg;7#2n9-18|S1;AK+ zgsn6;k6-%!QD>D?cFy}8F;r@z8H9xN1jsOBw2vQONVqBVEbkiNUqgw~*!^##ht>w0 zUOykwH=$LwX2j&nLy=@{hr)2O&-wm-NyjW7n~Zs9UlH;P7iP3 zI}S(r0YFVYacnKH(+{*)Tbw)@;6>%=&Th=+Z6NHo_tR|JCI8TJiXv2N7ei7M^Q+RM z?9o`meH$5Yi;@9XaNR#jIK^&{N|DYNNbtdb)XW1Lv2k{E>;?F`#Pq|&_;gm~&~Zc9 zf+6ZE%{x4|{YdtE?a^gKyzr}dA>OxQv+pq|@IXL%WS0CiX!V zm$fCePA%lU{%pTKD7|5NJHeXg=I0jL@$tOF@K*MI$)f?om)D63K*M|r`gb9edD1~Y zc|w7N)Y%do7=0{RC|AziW7#am$)9jciRJ?IWl9PE{G3U+$%FcyKs_0Cgq`=K3@ttV z9g;M!3z~f_?P%y3-ph%vBMeS@p7P&Ea8M@97+%XEj*(1E6vHj==d zjsoviB>j^$_^OI_DEPvFkVo(BGRo%cJeD){6Uckei=~1}>sp299|IRjhXe)%?uP0I zF5+>?0#Ye}T^Y$u_rc4=lPcq4K^D(TZG-w30-YiEM=dcK+4#o*>lJ8&JLi+3UcpZk z!^?95S^C0ja^jwP`|{<+3cBVog$(mRdQmadS+Vh~z zS@|P}=|z3P6uS+&@QsMp0no9Od&27O&14zHXGAOEy zh~OKpymK5C%;LLb467@KgIiVwYbYd6wFxI{0-~MOGfTq$nBTB!{SrWmL9Hs}C&l&l#m?s*{tA?BHS4mVKHAVMqm63H<|c5n0~k)-kbg zXidai&9ZUy0~WFYYKT;oe~rytRk?)r8bptITsWj(@HLI;@=v5|XUnSls7$uaxFRL+ zRVMGuL3w}NbV1`^=Pw*0?>bm8+xfeY(1PikW*PB>>Tq(FR`91N0c2&>lL2sZo5=VD zQY{>7dh_TX98L2)n{2OV=T10~*YzX27i2Q7W86M4$?gZIXZaBq#sA*{PH8){|GUi;oM>e?ua7eF4WFuFYZSG| zze?srg|5Ti8Og{O zeFxuw9!U+zhyk?@w zjsA6(oKD=Ka;A>Ca)oPORxK+kxH#O@zhC!!XS4@=swnuMk>t+JmLmFiE^1aX3f<)D@`%K0FGK^gg1a1j>zi z2KhV>sjU7AX3F$SEqrXSC}fRx64GDoc%!u2Yag68Lw@w9v;xOONf@o)Lc|Uh3<21ctTYu-mFZuHk*+R{GjXHIGq3p)tFtQp%TYqD=j1&y)>@zxoxUJ!G@ zgI0XKmP6MNzw>nRxK$-Gbzs}dyfFzt>#5;f6oR27ql!%+{tr+(`(>%51|k`ML} zY4eE)Lxq|JMas(;JibNQds1bUB&r}ydMQXBY4x(^&fY_&LlQC)3hylc$~8&~|06-D z#T+%66rYbHX%^KuqJED_wuGB+=h`nWA!>1n0)3wZrBG3%`b^Ozv6__dNa@%V14|!D zQ?o$z5u0^8`giv%qE!BzZ!3j;BlDlJDk)h@9{nSQeEk!z9RGW) z${RSF3phEM*ce*>Xdp}585vj$|40=&S{S-GTiE?Op*vY&Lvr9}BO$XWy80IF+6@%n z5*2ueT_g@ofP#u5pxb7n*fv^Xtt7&?SRc{*2Ka-*!BuOpf}neHGCiHy$@Ka1^Dint z;DkmIL$-e)rj4o2WQV%Gy;Xg(_Bh#qeOsTM2f@KEe~4kJ8kNLQ+;(!j^bgJMcNhvklP5Z6I+9Fq@c&D~8Fb-4rmDT!MB5QC{Dsb;BharP*O;SF4& zc$wj-7Oep7#$WZN!1nznc@Vb<_Dn%ga-O#J(l=OGB`dy=Sy&$(5-n3zzu%d7E#^8`T@}V+5B;PP8J14#4cCPw-SQTdGa2gWL0*zKM z#DfSXs_iWOMt)0*+Y>Lkd=LlyoHjublNLefhKBv@JoC>P7N1_#> zv=mLWe96%EY;!ZGSQDbZWb#;tzqAGgx~uk+-$+2_8U`!ypbwXl z^2E-FkM1?lY@yt8=J3%QK+xaZ6ok=-y%=KXCD^0r!5vUneW>95PzCkOPO*t}p$;-> ze5j-BLT_;)cZQzR2CEsm@rU7GZfFtdp*a|g4wDr%8?2QkIGasRfDWT-Dvy*U{?IHT z*}wGnzdlSptl#ZF^sf)KT|BJs&kLG91^A6ls{CzFprZ6-Y!V0Xysh%9p%iMd7HLsS zN+^Un$tDV)T@i!v?3o0Fsx2qI(AX_$dDkBzQ@fRM%n zRXk6hb9Py#JXUs+7)w@eo;g%QQ95Yq!K_d=z{0dGS+pToEI6=Bo8+{k$7&Z zo4>PH(`ce8E-Ps&uv`NQ;U$%t;w~|@E3WVOCi~R4oj5wP?%<*1C%}Jq%a^q~T7u>K zML5AKfQDv6>PuT`{SrKHRAF+^&edg6+5R_#H?Lz3iGoWo#PCEd0DS;)2U({{X#zU^ zw_xv{4x7|t!S)>44J;KfA|DC?;uQ($l+5Vp7oeqf7{GBF9356nx|&B~gs+@N^gSdd zvb*>&W)|u#F{Z_b`f#GVtQ`pYv3#||N{xj1NgB<#=Odt6{eB%#9RLt5v zIi|0u70`#ai}9fJjKv7dE!9ZrOIX!3{$z_K5FBd-Kp-&e4(J$LD-)NMTp^_pB`RT; zftVVlK2g@+1Ahv2$D){@Y#cL#dUj9*&%#6 zd2m9{1NYp>)6=oAvqdCn5#cx{AJ%S8skUgMglu2*IAtd+z1>B&`MuEAS(D(<6X#Lj z?f4CFx$)M&$=7*>9v1ER4b6!SIz-m0e{o0BfkySREchp?WdVPpQCh!q$t>?rL!&Jg zd#heM;&~A}VEm8Dvy&P|J*eAV&w!&Nx6HFV&B8jJFVTmgLaswn!cx$&%JbTsloz!3 zMEz1d`k==`Ueub_JAy_&`!ogbwx27^ZXgFNAbx=g_I~5nO^r)}&myw~+yY*cJl4$I znNJ32M&K=0(2Dj_>@39`3=FX!v3nZHno_@q^!y}%(yw0PqOo=);6Y@&ylVe>nMOZ~ zd>j#QQSBn3oaWd;qy$&5(5H$Ayi)0haAYO6TH>FR?rhqHmNOO+(})NB zLI@B@v0)eq!ug`>G<@htRlp3n!EpU|n+G+AvXFrWSUsLMBfL*ZB`CRsIVHNTR&b?K zxBgsN0BjfB>UVcJ|x%=-zb%OV7lmZc& zxiupadZVF7)6QuhoY;;FK2b*qL0J-Rn-8!X4ZY$-ZSUXV5DFd7`T41c(#lAeLMoeT z4%g655v@7AqT!i@)Edt5JMbN(=Q-6{=L4iG8RA%}w;&pKmtWvI4?G9pVRp|RTw`g0 zD5c12B&A2&P6Ng~8WM2eIW=wxd?r7A*N+&!Be7PX3s|7~z=APxm=A?5 zt>xB4WG|*Td@VX{Rs)PV0|yK`oI3^xn(4c_j&vgxk_Y3o(-`_5o`V zRTghg6%l@(qodXN;dB#+OKJEEvhfcnc#BeO2|E(5df-!fKDZ!%9!^BJ_4)9P+9Dq5 zK1=(v?KmIp34r?z{NEWnLB3Px{XYwy-akun4F7xTRr2^zeYW{gcK9)>aJDdU5;w5@ zak=<+-PLH-|04pelTb%ULpuuuJC7DgyT@D|p{!V!0v3KpDnRjANN12q6SUR3mb9<- z>2r~IApQGhstZ!3*?5V z8#)hJ0TdZg0M-BK#nGFP>$i=qk82DO z7h;Ft!D5E15OgW)&%lej*?^1~2=*Z5$2VX>V{x8SC+{i10BbtUk9@I#Vi&hX)q
Q!LwySI{Bnv%Sm)yh{^sSVJ8&h_D-BJ_YZe5eCaAWU9b$O2c z$T|{vWVRtOL!xC0DTc(Qbe`ItNtt5hr<)VijD0{U;T#bUEp381_y`%ZIav?kuYG{iyYdEBPW=*xNSc;Rlt6~F4M`5G+VtOjc z*0qGzCb@gME5udTjJA-9O<&TWd~}ysBd(eVT1-H82-doyH9RST)|+Pb{o*;$j9Tjs zhU!IlsPsj8=(x3bAKJTopW3^6AKROHR^7wZ185wJGVhA~hEc|LP;k7NEz-@4p5o}F z`AD6naG3(n=NF9HTH81=F+Q|JOz$7wm9I<+#BSmB@o_cLt2GkW9|?7mM;r!JZp89l zbo!Hp8=n!XH1{GwaDU+k)pGp`C|cXkCU5%vcH)+v@0eK>%7gWxmuMu9YLlChA|_D@ zi#5zovN_!a-0?~pUV-Rj*1P)KwdU-LguR>YM&*Nen+ln8Q$?WFCJg%DY%K}2!!1FE zDv-A%Cbwo^p(lzac&_TZ-l#9kq`mhLcY3h9ZTUVCM(Ad&=EriQY5{jJv<5K&g|*Lk zgV%ILnf1%8V2B0E&;Sp4sYbYOvvMebLwYwzkRQ#F8GpTQq#uv=J`uaSJ34OWITeSGo6+-8Xw znCk*n{kdDEi)Hi&u^)~cs@iyCkFWB2SWZU|Uc%^43ZIZQ-vWNExCCtDWjqHs;;tWf$v{}0{p0Rvxkq``)*>+Akq%|Na zA`@~-Vfe|+(AIlqru+7Ceh4nsVmO9p9jc8}HX^W&ViBDXT+uXbT#R#idPn&L>+#b6 zflC-4C5-X;kUnR~L>PSLh*gvL68}RBsu#2l`s_9KjUWRhiqF`j)`y`2`YU(>3bdBj z?>iyjEhe-~$^I5!nn%B6Wh+I`FvLNvauve~eX<+Ipl&04 zT}};W&1a3%W?dJ2=N#0t?e+aK+%t}5q%jSLvp3jZ%?&F}nOOWr>+{GFIa%wO_2`et z=JzoRR~}iKuuR+azPI8;Gf9)z3kyA4EIOSl!sRR$DlW}0>&?GbgPojmjmnln;cTqCt=ADbE zZ8GAnoM+S1(5$i8^O4t`ue;vO4i}z0wz-QEIVe5_u03;}-!G1NyY8;h^}y;tzY}i5 zqQr#Ur3Fy8sSa$Q0ys+f`!`+>9WbvU_I`Sj;$4{S>O3?#inLHCrtLy~!s#WXV=oVP zeE93*Nc`PBi4q@%Ao$x4lw9vLHM!6mn3-b_cebF|n-2vt-zYVF_&sDE--J-P;2WHo z+@n2areE0o$LjvjlV2X7ZU@j+`{*8zq`JR3gKF#EW|#+{nMyo-a>nFFTg&vhyT=b} zDa8+v0(Dgx0yRL@ZXOYIlVSZ0|MFizy0VPW8;AfA5|pe!#j zX}Py^8fl5SyS4g1WSKKtnyP+_PoOwMMwu`(i@Z)diJp~U54*-miOchy7Z35eL>^M z4p<-aIxH4VUZgS783@H%M7P9hX>t{|RU7$n4T(brCG#h9e9p! z+o`i;EGGq3&pF;~5V~eBD}lC)>if$w%Vf}AFxGqO88|ApfHf&Bvu+xdG)@vuF}Yvk z)o;~k-%+0K0g+L`Wala!$=ZV|z$e%>f0%XoLib%)!R^RoS+{!#X?h-6uu zF&&KxORdZU&EwQFITIRLo(7TA3W}y6X{?Y%y2j0It!ekU#<)$qghZtpcS>L3uh`Uj z7GY;6f$9qKynP#oS3$$a{p^{D+0oJQ71`1?OAn_m8)UGZmj3l*ZI)`V-a>MKGGFG< z&^jg#Ok%(hhm>hSrZ5;Qga4u(?^i>GiW_j9%_7M>j(^|Om$#{k+^*ULnEgzW_1gCICtAD^WpC`A z{9&DXkG#01Xo)U$OC(L5Y$DQ|Q4C6CjUKk1UkPj$nXH##J{c8e#K|&{mA*;b$r0E4 zUNo0jthwA(c&N1l=PEe8Rw_8cEl|-eya9z&H3#n`B$t#+aJ03RFMzrV@gowbe8v(c zIFM60^0&lCFO10NU4w@|61xiZ4CVXeaKjd;d?sv52XM*lS8XiVjgWpRB;&U_C0g+`6B5V&w|O6B*_q zsATxL!M}+$He)1eOWECce#eS@2n^xhlB4<_Nn?yCVEQWDs(r`|@2GqLe<#(|&P0U? z$7V5IgpWf09uIf_RazRwC?qEqRaHyL?iiS05UiGesJy%^>-C{{ypTBI&B0-iUYhk> zIk<5xpsuV@g|z(AZD+C-;A!fTG=df1=<%nxy(a(IS+U{ME4ZbDEBtcD_3V=icT6*_ z)>|J?>&6%nvHhZERBtjK+s4xnut*@>GAmA5m*OTp$!^CHTr}vM4n(X1Q*;{e-Rd2BCF-u@1ZGm z!S8hJ6L=Gl4T_SDa7Xx|-{4mxveJg=ctf`BJ*fy!yF6Dz&?w(Q_6B}WQVtNI!BVBC zKfX<>7vd6C96}XAQmF-Jd?1Q4eTfRB3q7hCh0f!(JkdWT5<{iAE#dKy*Jxq&3a1@~ z8C||Dn2mFNyrUV|<-)C^_y7@8c2Fz+2jrae9deBDu;U}tJ{^xAdxCD248(k;dCJ%o z`y3sADe>U%suxwwv~8A1+R$VB=Q?%U?4joI$um;aH+eCrBqpn- z%79D_7rb;R-;-9RTrwi9dPlg8&@tfWhhZ(Vx&1PQ+6(huX`;M9x~LrW~~#3{j0Bh2kDU$}@!fFQej4VGkJv?M4rU^x!RU zEwhu$!CA_iDjFjrJa`aocySDX16?~;+wgav;}Zut6Mg%C4>}8FL?8)Kgwc(Qlj{@#2Pt0?G`$h7P#M+qoXtlV@d}%c&OzO+QYKK`kyXaK{U(O^2DyIXCZlNQjt0^8~8JzNGrIxhj}}M z&~QZlbx%t;MJ(Vux;2tgNKGlAqphLq%pd}JG9uoVHUo?|hN{pLQ6Em%r*+7t^<);X zm~6=qChlNAVXNN*Sow->*4;}T;l;D1I-5T{Bif@4_}=>l`tK;qqDdt5zvisCKhMAH z#r}`)7VW?LZqfdmXQ%zo5bJ00{Xb9^YKrk0Nf|oIW*K@(=`o2Vndz}ZDyk{!u}PVx zzd--+_WC*U{~DH3{?GI64IB+@On&@9X>EUAo&L+G{L^dozaI4C3G#2wr~hseW@K&g zKWs{uHu-9Je!3;4pE>eBltKUXb^*hG8I&413)$J&{D4N%7PcloU6bn%jPxJyQL?g* z9g+YFFEDiE`8rW^laCNzQmi7CTnPfwyg3VDHRAl>h=In6jeaVOP@!-CP60j3+#vpL zEYmh_oP0{-gTe7Or`L6x)6w?77QVi~jD8lWN@3RHcm80iV%M1A!+Y6iHM)05iC64tb$X2lV_%Txk@0l^hZqi^%Z?#- zE;LE0uFx)R08_S-#(wC=dS&}vj6P4>5ZWjhthP=*Hht&TdLtKDR;rXEX4*z0h74FA zMCINqrh3Vq;s%3MC1YL`{WjIAPkVL#3rj^9Pj9Ss7>7duy!9H0vYF%>1jh)EPqvlr6h%R%CxDsk| z!BACz7E%j?bm=pH6Eaw{+suniuY7C9Ut~1cWfOX9KW9=H><&kQlinPV3h9R>3nJvK z4L9(DRM=x;R&d#a@oFY7mB|m8h4692U5eYfcw|QKwqRsshN(q^v$4$)HgPpAJDJ`I zkqjq(8Cd!K!+wCd=d@w%~e$=gdUgD&wj$LQ1r>-E=O@c ze+Z$x{>6(JA-fNVr)X;*)40Eym1TtUZI1Pwwx1hUi+G1Jlk~vCYeXMNYtr)1?qwyg zsX_e*$h?380O00ou?0R@7-Fc59o$UvyVs4cUbujHUA>sH!}L54>`e` zHUx#Q+Hn&Og#YVOuo*niy*GU3rH;%f``nk#NN5-xrZ34NeH$l`4@t);4(+0|Z#I>Y z)~Kzs#exIAaf--65L0UHT_SvV8O2WYeD>Mq^Y6L!Xu8%vnpofG@w!}R7M28?i1*T&zp3X4^OMCY6(Dg<-! zXmcGQrRgHXGYre7GfTJ)rhl|rs%abKT_Nt24_Q``XH{88NVPW+`x4ZdrMuO0iZ0g` z%p}y};~T5gbb9SeL8BSc`SO#ixC$@QhXxZ=B}L`tP}&k?1oSPS=4%{UOHe0<_XWln zwbl5cn(j-qK`)vGHY5B5C|QZd5)W7c@{bNVXqJ!!n$^ufc?N9C-BF2QK1(kv++h!>$QbAjq)_b$$PcJdV+F7hz0Hu@ zqj+}m0qn{t^tD3DfBb~0B36|Q`bs*xs|$i^G4uNUEBl4g;op-;Wl~iThgga?+dL7s zUP(8lMO?g{GcYpDS{NM!UA8Hco?#}eNEioRBHy4`mq!Pd-9@-97|k$hpEX>xoX+dY zDr$wfm^P&}Wu{!%?)U_(%Mn79$(ywvu*kJ9r4u|MyYLI_67U7%6Gd_vb##Nerf@>& z8W11z$$~xEZt$dPG}+*IZky+os5Ju2eRi;1=rUEeIn>t-AzC_IGM-IXWK3^6QNU+2pe=MBn4I*R@A%-iLDCOHTE-O^wo$sL_h{dcPl=^muAQb`_BRm};=cy{qSkui;`WSsj9%c^+bIDQ z0`_?KX0<-=o!t{u(Ln)v>%VGL z0pC=GB7*AQ?N7N{ut*a%MH-tdtNmNC+Yf$|KS)BW(gQJ*z$d{+{j?(e&hgTy^2|AR9vx1Xre2fagGv0YXWqtNkg*v%40v?BJBt|f9wX5 z{QTlCM}b-0{mV?IG>TW_BdviUKhtosrBqdfq&Frdz>cF~yK{P@(w{Vr7z2qKFwLhc zQuogKO@~YwyS9%+d-zD7mJG~@?EFJLSn!a&mhE5$_4xBl&6QHMzL?CdzEnC~C3$X@ zvY!{_GR06ep5;<#cKCSJ%srxX=+pn?ywDwtJ2{TV;0DKBO2t++B(tIO4)Wh`rD13P z4fE$#%zkd=UzOB74gi=-*CuID&Z3zI^-`4U^S?dHxK8fP*;fE|a(KYMgMUo`THIS1f!*6dOI2 zFjC3O=-AL`6=9pp;`CYPTdVX z8(*?V&%QoipuH0>WKlL8A*zTKckD!paN@~hh zmXzm~qZhMGVdQGd=AG8&20HW0RGV8X{$9LldFZYm zE?}`Q3i?xJRz43S?VFMmqRyvWaS#(~Lempg9nTM$EFDP(Gzx#$r)W&lpFKqcAoJh-AxEw$-bjW>`_+gEi z2w`99#UbFZGiQjS8kj~@PGqpsPX`T{YOj`CaEqTFag;$jY z8_{Wzz>HXx&G*Dx<5skhpETxIdhKH?DtY@b9l8$l?UkM#J-Snmts7bd7xayKTFJ(u zyAT&@6cAYcs{PBfpqZa%sxhJ5nSZBPji?Zlf&}#L?t)vC4X5VLp%~fz2Sx<*oN<7` z?ge=k<=X7r<~F7Tvp9#HB{!mA!QWBOf%EiSJ6KIF8QZNjg&x~-%e*tflL(ji_S^sO ztmib1rp09uon}RcsFi#k)oLs@$?vs(i>5k3YN%$T(5Or(TZ5JW9mA6mIMD08=749$ z!d+l*iu{Il7^Yu}H;lgw=En1sJpCKPSqTCHy4(f&NPelr31^*l%KHq^QE>z>Ks_bH zjbD?({~8Din7IvZeJ>8Ey=e;I?thpzD=zE5UHeO|neioJwG;IyLk?xOz(yO&0DTU~ z^#)xcs|s>Flgmp;SmYJ4g(|HMu3v7#;c*Aa8iF#UZo7CvDq4>8#qLJ|YdZ!AsH%^_7N1IQjCro

K7UpUK$>l@ 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 E2O(~oYXATM literal 54329 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

<5G2M1WZP5 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 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/kotlin/inr/numass/trapping/FunctionCache.kt b/src/main/kotlin/ru/inr/mass/trapping/FunctionCache.kt similarity index 63% rename from src/main/kotlin/inr/numass/trapping/FunctionCache.kt rename to src/main/kotlin/ru/inr/mass/trapping/FunctionCache.kt index 88a235e..75460cb 100644 --- a/src/main/kotlin/inr/numass/trapping/FunctionCache.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/FunctionCache.kt @@ -1,23 +1,23 @@ -package inr.numass.trapping - -import java.util.* - -class FunctionCache(val xPrecision: Double, val function: (Double) -> Double) { - private val values = TreeMap() - - operator fun invoke(x: Double): Double { - val floor: MutableMap.MutableEntry? = values.floorEntry(x) - val ceil: MutableMap.MutableEntry? = values.ceilingEntry(x) - if (floor == null || ceil == null || ceil.key - floor.key <= xPrecision) { - val newValue = function(x) - values[x] = newValue - return newValue - } else { - val x0 = floor.key - val x1 = ceil.key - val y0 = floor.value - val y1 = ceil.value - return y0 + (x - x0) * (y1 - y0) / (x1 - x0) - } - } +package ru.inr.mass.trapping + +import java.util.* + +class FunctionCache(private val xPrecision: Double, val function: (Double) -> Double) { + private val values = TreeMap() + + operator fun invoke(x: Double): Double { + val floor: MutableMap.MutableEntry? = values.floorEntry(x) + val ceil: MutableMap.MutableEntry? = values.ceilingEntry(x) + return if (floor == null || ceil == null || ceil.key - floor.key <= xPrecision) { + val newValue = function(x) + values[x] = newValue + newValue + } else { + val x0 = floor.key + val x1 = ceil.key + val y0 = floor.value + val y1 = ceil.value + y0 + (x - x0) * (y1 - y0) / (x1 - x0) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/inr/numass/trapping/MultiCounter.kt b/src/main/kotlin/ru/inr/mass/trapping/MultiCounter.kt similarity index 93% rename from src/main/kotlin/inr/numass/trapping/MultiCounter.kt rename to src/main/kotlin/ru/inr/mass/trapping/MultiCounter.kt index b6c3f2c..9194b97 100644 --- a/src/main/kotlin/inr/numass/trapping/MultiCounter.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/MultiCounter.kt @@ -1,96 +1,96 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package inr.numass.trapping - -import java.io.PrintStream -import java.lang.Integer.valueOf -import java.util.HashMap - -/** - * TODO есть объект MultiDimensionalCounter, исползовать его? - * - * @author Alexander Nozik - * @version $Id: $Id - */ -class MultiCounter(private var name: String) { - - private var counts = HashMap() - - /** - * - * getCount. - * - * @param name a [java.lang.String] object. - * @return a int. - */ - fun getCount(name: String): Int? { - return counts[name] - } - - /** - * - * increase. - * - * @param name a [java.lang.String] object. - */ - @Synchronized - fun increase(name: String) { - if (counts.containsKey(name)) { - val count = counts[name] - counts.remove(name) - counts[name] = count!! + 1 - } else { - counts[name] = valueOf(1) - } - - } - - /** - * - * print. - * - * @param out a [java.io.PrintWriter] object. - */ - fun print(out: PrintStream) { - out.printf("%nValues for counter %s%n%n", this.name) - for ((keyName, value) in counts) { - - out.printf("%s : %d%n", keyName, value) - } - } - - /** - * - * reset. - * - * @param name a [java.lang.String] object. - */ - @Synchronized - fun reset(name: String) { - if (counts.containsKey(name)) { - counts.remove(name) - } - } - - /** - * - * resetAll. - */ - @Synchronized - fun resetAll() { - this.counts = HashMap() - } -} +/* + * Copyright 2015 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ru.inr.mass.trapping + +import java.io.PrintStream +import java.lang.Integer.valueOf +import java.util.* + +/** + * TODO есть объект MultiDimensionalCounter, исползовать его? + * + * @author Alexander Nozik + * @version $Id: $Id + */ +class MultiCounter(private var name: String) { + + private var counts = HashMap() + + /** + * + * getCount. + * + * @param name a [java.lang.String] object. + * @return a int. + */ + fun getCount(name: String): Int? { + return counts[name] + } + + /** + * + * increase. + * + * @param name a [java.lang.String] object. + */ + @Synchronized + fun increase(name: String) { + if (counts.containsKey(name)) { + val count = counts[name] + counts.remove(name) + counts[name] = count!! + 1 + } else { + counts[name] = valueOf(1) + } + + } + + /** + * + * print. + * + * @param out a [java.io.PrintWriter] object. + */ + fun print(out: PrintStream) { + out.printf("%nValues for counter %s%n%n", this.name) + for ((keyName, value) in counts) { + + out.printf("%s : %d%n", keyName, value) + } + } + + /** + * + * reset. + * + * @param name a [java.lang.String] object. + */ + @Synchronized + fun reset(name: String) { + if (counts.containsKey(name)) { + counts.remove(name) + } + } + + /** + * + * resetAll. + */ + @Synchronized + fun resetAll() { + this.counts = HashMap() + } +} diff --git a/src/main/kotlin/inr/numass/trapping/RandomGeneratorBridge.kt b/src/main/kotlin/ru/inr/mass/trapping/RandomGeneratorBridge.kt similarity index 85% rename from src/main/kotlin/inr/numass/trapping/RandomGeneratorBridge.kt rename to src/main/kotlin/ru/inr/mass/trapping/RandomGeneratorBridge.kt index 56bf65e..939c963 100644 --- a/src/main/kotlin/inr/numass/trapping/RandomGeneratorBridge.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/RandomGeneratorBridge.kt @@ -1,28 +1,28 @@ -package inr.numass.trapping - -import org.apache.commons.math3.random.RandomGenerator -import org.apache.commons.rng.UniformRandomProvider - -class RandomGeneratorBridge(val provider: UniformRandomProvider) : RandomGenerator { - override fun nextBoolean(): Boolean = provider.nextBoolean() - - override fun nextFloat(): Float = provider.nextFloat() - - override fun setSeed(seed: Int) = error("Not supported") - - override fun setSeed(seed: IntArray?) = error("Not supported") - - override fun setSeed(seed: Long) = error("Not supported") - - override fun nextBytes(bytes: ByteArray) = provider.nextBytes(bytes) - - override fun nextInt(): Int = provider.nextInt() - - override fun nextInt(n: Int): Int = provider.nextInt(n) - - override fun nextGaussian(): Double = error("Not supported") - - override fun nextDouble(): Double = provider.nextDouble() - - override fun nextLong(): Long = provider.nextLong() +package ru.inr.mass.trapping + +import org.apache.commons.math3.random.RandomGenerator +import org.apache.commons.rng.UniformRandomProvider + +class RandomGeneratorBridge(private val provider: UniformRandomProvider) : RandomGenerator { + override fun nextBoolean(): Boolean = provider.nextBoolean() + + override fun nextFloat(): Float = provider.nextFloat() + + override fun setSeed(seed: Int) = error("Not supported") + + override fun setSeed(seed: IntArray?) = error("Not supported") + + override fun setSeed(seed: Long) = error("Not supported") + + override fun nextBytes(bytes: ByteArray) = provider.nextBytes(bytes) + + override fun nextInt(): Int = provider.nextInt() + + override fun nextInt(n: Int): Int = provider.nextInt(n) + + override fun nextGaussian(): Double = error("Not supported") + + override fun nextDouble(): Double = provider.nextDouble() + + override fun nextLong(): Long = provider.nextLong() } \ No newline at end of file diff --git a/src/main/kotlin/inr/numass/trapping/Scatter.kt b/src/main/kotlin/ru/inr/mass/trapping/Scatter.kt similarity index 97% rename from src/main/kotlin/inr/numass/trapping/Scatter.kt rename to src/main/kotlin/ru/inr/mass/trapping/Scatter.kt index cbe576f..bddd60f 100644 --- a/src/main/kotlin/inr/numass/trapping/Scatter.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/Scatter.kt @@ -1,983 +1,982 @@ -package inr.numass.trapping - -import org.apache.commons.math3.random.RandomGenerator -import org.apache.commons.math3.util.FastMath.* -import org.apache.commons.math3.util.Pair - -/** - * - * The initial code was written by Ferenc Glueck and then rewritten by [Sebastian Voecking](mailto:seb.voeck@uni-muenster.de) - * into C++. To reference the code, don't forget to also include [kasiopea](http://stacks.iop.org/1367-2630/19/i=5/a=053012). - * @author Darksnake - */ -object Scatter { - - var debug = false - - val counter = MultiCounter("Accept-reject calls") - - - private val a02 = 28e-22 // Bohr radius squared - private val clight = 137.0 // velocity of light in atomic units - private val emass = 18780.0 // Electron mass in atomic units - private val R = 13.6 // Ryberg energy in eV - - private fun count(counterName: String) { - if (debug) { - counter.increase(counterName) - } - } - - fun randomel(E: Double, generator: RandomGenerator): Pair { - // This subroutine generates energy loss and polar scatt. angle according to - // electron elastic scattering in molecular hydrogen. - // Input: - // E: incident electron energy in eV. - // Output: - // *Eloss: energy loss in eV - // *theta: change of polar angle in degrees - val H2molmass = 69e6 - val T: Double = E / 27.2 - var c = 1.0 - val b: Double - var G: Double - var a: Double - val gam: Double - var K2: Double - val Gmax: Double = when { - E >= 250.0 -> 1e-19 - E < 250.0 && E >= 150.0 -> 2.5e-19 - else -> 1e-18 - } - var i: Int = 1 - - count("randomel-calls") - gam = 1.0 + T / (clight * clight) // relativistic correction factor - b = 2.0 / (1.0 + gam) / T - while (i < 5000) { - count("randomel") - c = 1.0 + b - b * (2.0 + b) / (b + 2.0 * generator.nextDouble()) - K2 = 2.0 * T * (1.0 + gam) * abs(1.0 - c) // momentum transfer squared - a = (4.0 + K2) * (4.0 + K2) / (gam * gam) - G = a * dElastic(E, c) - if (G > Gmax * generator.nextDouble()) { - break - } - i++ - } - return Pair(2.0 * emass / H2molmass * (1.0 - c) * E, acos(c) * 180.0 / Math.PI) - } - - - // Energy values of the excited electronic states: - // (from Mol. Phys. 41 (1980) 1501, in Hartree atomic units) - private val En = doubleArrayOf(12.73 / 27.2, 13.2 / 27.2, 14.77 / 27.2, 15.3 / 27.2, 14.93 / 27.2, 15.4 / 27.2, 13.06 / 27.2) - // Probability numbers of the electronic states: - // (from testelectron7.c calculation ) - private val p = doubleArrayOf(35.86, 40.05, 6.58, 2.26, 9.61, 4.08, 1.54) - // Energy values of the B vibrational states: - // (from: Phys. Rev. A51 (1995) 3745 , in Hartree atomic units) - private val EB = doubleArrayOf(0.411, 0.417, 0.423, 0.428, 0.434, 0.439, 0.444, 0.449, 0.454, 0.459, 0.464, 0.468, 0.473, 0.477, 0.481, 0.485, 0.489, 0.493, 0.496, 0.500, 0.503, 0.507, 0.510, 0.513, 0.516, 0.519, 0.521, 0.524) - // Energy values of the C vibrational states: - // (from: Phys. Rev. A51 (1995) 3745 , in Hartree atomic units) - private val EC = doubleArrayOf(0.452, 0.462, 0.472, 0.481, 0.490, 0.498, 0.506, 0.513, 0.519, 0.525, 0.530, 0.534, 0.537, 0.539) - // Franck-Condon factors of the B vibrational states: - // (from: Phys. Rev. A51 (1995) 3745 ) - private val pB = doubleArrayOf(4.2e-3, 1.5e-2, 3.0e-2, 4.7e-2, 6.3e-2, 7.3e-2, 7.9e-2, 8.0e-2, 7.8e-2, 7.3e-2, 6.6e-2, 5.8e-2, 5.1e-2, 4.4e-2, 3.7e-2, 3.1e-2, 2.6e-2, 2.2e-2, 1.8e-2, 1.5e-2, 1.3e-2, 1.1e-2, 8.9e-3, 7.4e-3, 6.2e-3, 5.2e-3, 4.3e-3, 3.6e-3) - // Franck-Condon factors of the C vibrational states: - // (from: Phys. Rev. A51 (1995) 3745 ) - private val pC = doubleArrayOf(1.2e-1, 1.9e-1, 1.9e-1, 1.5e-1, 1.1e-1, 7.5e-2, 5.0e-2, 3.3e-2, 2.2e-2, 1.4e-2, 9.3e-3, 6.0e-3, 3.7e-3, 1.8e-3) - - private val Ecen = 12.6 / 27.21 - - private val fmax by lazy { - val sum = DoubleArray(1001) - - val T: Double = 20000.0 / 27.2 - val xmin = Ecen * Ecen / (2.0 * T) - val ymin = log(xmin) - val ymax = log(8.0 * T + xmin) - val dy = (ymax - ymin) / 1000.0 - - - var res = 0.0 - var i = 0 - while (i <= 1000) { - val y = ymin + dy * i - val K = exp(y / 2.0) - sum[i] = sumexc(K) - if (sum[i] > res) { - res = sum[i] - } - i++ - } - res *= 1.05 - res - } - - - fun randomexc(E: Double, generator: RandomGenerator): Pair { - // This subroutine generates energy loss and polar scatt. angle according to - // electron excitation scattering in molecular hydrogen. - // Input: - // E: incident electron energy in eV. - // Output: - // *Eloss: energy loss in eV - // *theta: change of polar angle in degrees - - - var c = 0.0 - var K: Double - var y: Double - var fy: Double - var pmax: Double - var D: Double - var j: Int - var n = 0 - var N: Int - var v = 0 - - count("randomexc-calls") - - // - // Scattering angle *theta generation: - // - val T = E / 27.2 - val theta: Double - if (E >= 100.0) { - val xmin = Ecen * Ecen / (2.0 * T) - val ymin = log(xmin) - val ymax = log(8.0 * T + xmin) - // dy = (ymax - ymin) / 1000.; - // Generation of y values with the Neumann acceptance-rejection method: - y = ymin - j = 1 - while (j < 5000) { - count("randomexc1") - y = ymin + (ymax - ymin) * generator.nextDouble() - K = exp(y / 2.0) - fy = sumexc(K) - if (fmax * generator.nextDouble() < fy) { - break - } - j++ - } - // Calculation of c=cos(theta) and theta: - val x = exp(y) - c = 1.0 - (x - xmin) / (4.0 * T) - theta = acos(c) * 180.0 / Math.PI - } else { - val Dmax = when { - E <= 25.0 -> 60.0 - E > 25.0 && E <= 35.0 -> 95.0 - E > 35.0 && E <= 50.0 -> 150.0 - else -> 400.0 - } - j = 1 - - while (j < 5000) { - count("randomexc2") - c = -1.0 + 2.0 * generator.nextDouble() - D = dExcitation(E, c) * 1e22 - if (Dmax * generator.nextDouble() < D) { - break - } - j++ - } - theta = acos(c) * 180.0 / Math.PI - } - // Energy loss *Eloss generation: - - // First we generate the electronic state, using the Neumann - // acceptance-rejection method for discrete distribution: - N = 7 // the number of electronic states in our calculation - pmax = p[1] // the maximum of the p[] values - j = 1 - while (j < 5000) { - count("randomexc3") - n = (N * generator.nextDouble()).toInt() - if (generator.nextDouble() * pmax < p[n]) { - break - } - j++ - }// Bp, Bpp, D, Dp, EF states - // C state; we generate now a vibrational state, - // using the Franck-Condon factors - // the number of C vibrational states in our calculation - // maximum of the pC[] values - // B state; we generate now a vibrational state, - // using the Frank-Condon factors - // the number of B vibrational states in our calculation - // maximum of the pB[] values - when { - n < 0 -> n = 0 - n > 6 -> n = 6 - } - val Eloss: Double - when (n) { - 0 -> { - // B state; we generate now a vibrational state, - // using the Frank-Condon factors - N = 28 // the number of B vibrational states in our calculation - pmax = pB[7] // maximum of the pB[] values - j = 1 - while (j < 5000) { - count("randomexc4") - v = (N * generator.nextDouble()).toInt() - if (generator.nextDouble() * pmax < pB[v]) { - break - } - j++ - } - if (v < 0) { - v = 0 - } - if (v > 27) { - v = 27 - } - Eloss = EB[v] * 27.2 - } - 1 -> { - // C state; we generate now a vibrational state, - // using the Franck-Condon factors - N = 14 // the number of C vibrational states in our calculation - pmax = pC[1] // maximum of the pC[] values - j = 1 - while (j < 5000) { - count("randomexc4") - v = (N * generator.nextDouble()).toInt() - if (generator.nextDouble() * pmax < pC[v]) { - break - } - j++ - } - if (v < 0) { - v = 0 - } - if (v > 13) { - v = 13 - } - Eloss = EC[v] * 27.2 - } - else -> - // Bp, Bpp, D, Dp, EF states - Eloss = En[n] * 27.2 - } - return Pair(Eloss, theta) - } - - fun randomion(E: Double, generator: RandomGenerator): Pair { - // This subroutine generates energy loss and polar scatt. angle according to - // electron ionization scattering in molecular hydrogen. - // Input: - // E: incident electron energy in eV. - // Output: - // *Eloss: energy loss in eV - // *theta: change of polar angle in degrees - // The kinetic energy of the secondary electron is: Eloss-15.4 eV - // - val Ei = 15.45 / 27.21 - var c: Double - val b: Double - var K: Double - val xmin: Double - val ymin: Double - val ymax: Double - val x: Double - var y: Double - val T: Double = E / 27.2 - var G: Double - var Gmax: Double - var q: Double - val h: Double - var F: Double - val Fmin: Double - val Fmax: Double - var Gp: Double - val Elmin: Double - val Elmax: Double = (E + 15.45) / 2.0 / 27.2 - val qmin: Double - val qmax: Double - var El: Double - val wmax: Double - var WcE: Double - var Jstarq: Double - var WcstarE: Double - var w: Double - var D2ion: Double - var j: Int = 1 - var K2: Double - var KK: Double - var fE: Double - var kej: Double - var ki: Double - var kf: Double - var Rex: Double - var arg: Double - var arctg: Double - var i: Int - var st1: Double - var st2: Double - count("randomion-calls") - // - // I. Generation of theta - // ----------------------- - Gmax = 1e-20 - if (E < 200.0) { - Gmax = 2e-20 - } - xmin = Ei * Ei / (2.0 * T) - b = xmin / (4.0 * T) - ymin = log(xmin) - ymax = log(8.0 * T + xmin) - // Generation of y values with the Neumann acceptance-rejection method: - y = ymin - while (j < 5000) { - count("randomion1") - y = ymin + (ymax - ymin) * generator.nextDouble() - K = exp(y / 2.0) - c = 1.0 + b - K * K / (4.0 * T) - G = K * K * (dInelastic(E, c) - dExcitation(E, c)) - if (Gmax * generator.nextDouble() < G) { - break - } - j++ - } - // y --> x --> c --> theta - x = exp(y) - c = 1.0 - (x - xmin) / (4.0 * T) - val theta = acos(c) * 180.0 / Math.PI - // - // II. Generation of Eloss, for fixed theta - // ---------------------------------------- - // - // For E<=100 eV we use subr. gensecelen - // (in this case no correlation between theta and Eloss) - if (E <= 100.0) { - return Pair(15.45 + gensecelen(E, generator), theta) - } - // For theta>=20 the free electron model is used - // (with full correlation between theta and Eloss) - if (theta >= 20.0) { - return Pair(E * (1.0 - c * c), theta) - } - // For E>100 eV and theta<20: analytical first Born approximation - // formula of Bethe for H atom (with modification for H2) - // - // Calc. of wmax: - if (theta >= 0.7) { - wmax = 1.1 - } else if (theta <= 0.7 && theta > 0.2) { - wmax = 2.0 - } else if (theta <= 0.2 && theta > 0.05) { - wmax = 4.0 - } else { - wmax = 8.0 - } - // We generate the q value according to the Jstarq pdf. We have to - // define the qmin and qmax limits for this generation: - K = sqrt(4.0 * T * (1.0 - Ei / (2.0 * T) - sqrt(1.0 - Ei / T) * c)) - Elmin = Ei - qmin = Elmin / K - K / 2.0 - qmax = Elmax / K - K / 2.0 - // - q = qmax - Fmax = 1.0 / 2.0 + 1.0 / Math.PI * (q / (1.0 + q * q) + atan(q)) - q = qmin - Fmin = 1.0 / 2.0 + 1.0 / Math.PI * (q / (1.0 + q * q) + atan(q)) - h = Fmax - Fmin - // Generation of Eloss with the Neumann acceptance-rejection method: - El = 0.0 - j = 1 - while (j < 5000) { - // Generation of q with inverse transform method - // (we use the Newton-Raphson method in order to solve the nonlinear eq. - // for the inversion) : - count("randomion2") - F = Fmin + h * generator.nextDouble() - y = 0.0 - i = 1 - while (i <= 30) { - G = 1.0 / 2.0 + (y + sin(2.0 * y) / 2.0) / Math.PI - Gp = (1.0 + cos(2.0 * y)) / Math.PI - y -= (G - F) / Gp - if (abs(G - F) < 1e-8) { - break - } - i++ - } - q = tan(y) - // We have the q value, so we can define El, and calculate the weight: - El = q * K + K * K / 2.0 - // First Born approximation formula of Bethe for e-H ionization: - KK = K - ki = sqrt(2.0 * T) - kf = sqrt(2.0 * (T - El)) - K2 = 4.0 * T * (1.0 - El / (2.0 * T) - sqrt(1.0 - El / T) * c) - if (K2 < 1e-9) { - K2 = 1e-9 - } - K = sqrt(K2) // momentum transfer - Rex = 1.0 - K * K / (kf * kf) + K2 * K2 / (kf * kf * kf * kf) - kej = sqrt(2.0 * abs(El - Ei) + 1e-8) - st1 = K2 - 2.0 * El + 2.0 - if (abs(st1) < 1e-9) { - st1 = 1e-9 - } - arg = 2.0 * kej / st1 - arctg = if (arg >= 0.0) { - atan(arg) - } else { - atan(arg) + Math.PI - } - st1 = (K + kej) * (K + kej) + 1.0 - st2 = (K - kej) * (K - kej) + 1.0 - fE = 1024.0 * El * (K2 + 2.0 / 3.0 * El) / (st1 * st1 * st1 * st2 * st2 * st2) * exp(-2.0 / kej * arctg) / (1.0 - exp(-2.0 * Math.PI / kej)) - D2ion = 2.0 * kf / ki * Rex / (El * K2) * fE - K = KK - // - WcE = D2ion - Jstarq = 16.0 / (3.0 * Math.PI * (1.0 + q * q) * (1.0 + q * q)) - WcstarE = 4.0 / (K * K * K * K * K) * Jstarq - w = WcE / WcstarE - if (wmax * generator.nextDouble() < w) { - break - } - j++ - } - - return Pair(El * 27.2, theta) - } - - private fun gensecelen(E: Double, generator: RandomGenerator): Double { - // This subroutine generates secondary electron energy W - // from ionization of incident electron energy E, by using - // the Lorentzian of Aseev et al. (Eq. 8). - // E and W in eV. - val Ei = 15.45 - val eps2 = 14.3 - val b = 6.25 - val B: Double = atan((Ei - eps2) / b) - val D: Double - val A: Double - val eps: Double - val a: Double - val u: Double = generator.nextDouble() - val epsmax: Double - - epsmax = (E + Ei) / 2.0 - A = atan((epsmax - eps2) / b) - D = b / (A - B) - a = b / D * (u + D / b * B) - eps = eps2 + b * tan(a) - return eps - Ei - } - - - // This subroutine computes the differential cross section - // dElastic= d sigma/d Omega of elastic electron scattering - // on molecular hydrogen. - // See: Nishimura et al., J. Phys. Soc. Jpn. 54 (1985) 1757. - // Input: E= electron kinetic energy in eV - // c= cos(theta), where theta is the polar scatt. angle - // dElastic: in m^2/steradian - private val elasticCel = doubleArrayOf(-0.512, -0.512, -0.509, -0.505, -0.499, -0.491, -0.476, -0.473, -0.462, -0.452, -0.438, -0.422, -0.406, -0.388, -0.370, -0.352, -0.333, -0.314, -0.296, -0.277, -0.258, -0.239, -0.221, -0.202, -0.185, -0.167, -0.151, -0.135, -0.120, -0.105, -0.092, -0.070, -0.053, -0.039, -0.030, -0.024, -0.019, -0.016, -0.014, -0.013, -0.012, -0.009, -0.008, -0.006, -0.005, -0.004, -0.003, -0.002, -0.002, -0.001) - private val elasticE = doubleArrayOf(0.0, 3.0, 6.0, 12.0, 20.0, 32.0, 55.0, 85.0, 150.0, 250.0) - private val elasticT = doubleArrayOf(0.0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 140.0, 180.0) - private val elasticD = arrayOf( - doubleArrayOf(2.9, 2.7, 2.5, 2.1, 1.8, 1.2, 0.9, 1.0, 1.6, 1.9), - doubleArrayOf(4.2, 3.6, 3.1, 2.5, 1.9, 1.1, 0.8, 0.9, 1.3, 1.4), - doubleArrayOf(6.0, 4.4, 3.2, 2.3, 1.8, 1.1, 0.7, 0.54, 0.5, 0.6), - doubleArrayOf(6.0, 4.1, 2.8, 1.9, 1.3, 0.6, 0.3, 0.17, 0.16, 0.23), - doubleArrayOf(4.9, 3.2, 2.0, 1.2, 0.8, 0.3, 0.15, 0.09, 0.05, 0.05), - doubleArrayOf(5.2, 2.5, 1.2, 0.64, 0.36, 0.13, 0.05, 0.03, 0.016, 0.02), - doubleArrayOf(4.0, 1.7, 0.7, 0.3, 0.16, 0.05, 0.02, 0.013, 0.01, 0.01), - doubleArrayOf(2.8, 1.1, 0.4, 0.15, 0.07, 0.02, 0.01, 0.007, 0.004, 0.003), - doubleArrayOf(1.2, 0.53, 0.2, 0.08, 0.03, 0.0074, 0.003, 0.0016, 0.001, 0.0008) - ) - - - private fun dElastic(E: Double, c: Double): Double { - val T: Double = E / 27.2 - var K2: Double - var K: Double - val d: Double - val st1: Double - val st2: Double - val DH: Double - val gam: Double - var Delreturn = 0.0 - val CelK: Double - val Ki: Double - val theta: Double - var i: Int - var j: Int - if (E >= 250.0) { - gam = 1.0 + T / (clight * clight) // relativistic correction factor - K2 = 2.0 * T * (1.0 + gam) * (1.0 - c) - if (K2 < 0.0) { - K2 = 1e-30 - } - K = sqrt(K2) - if (K < 1e-9) { - K = 1e-9 // momentum transfer - } - d = 1.4009 // distance of protons in H2 - st1 = 8.0 + K2 - st2 = 4.0 + K2 - // DH is the diff. cross section for elastic electron scatt. - // on atomic hydrogen within the first Born approximation : - DH = 4.0 * st1 * st1 / (st2 * st2 * st2 * st2) * a02 - // CelK calculation with linear interpolation. - // CelK is the correction of the elastic electron - // scatt. on molecular hydrogen compared to the independent atom - // model. - when { - K < 3.0 -> { - i = (K / 0.1).toInt() - Ki = i * 0.1 - CelK = elasticCel[i] + (K - Ki) / 0.1 * (elasticCel[i + 1] - elasticCel[i]) - } - K >= 3.0 && K < 5.0 -> { - i = (30 + (K - 3.0) / 0.2).toInt() - Ki = 3.0 + (i - 30) * 0.2 - CelK = elasticCel[i] + (K - Ki) / 0.2 * (elasticCel[i + 1] - elasticCel[i]) - } - K >= 5.0 && K < 9.49 -> { - i = (40 + (K - 5.0) / 0.5).toInt() - Ki = 5.0 + (i - 40) * 0.5 - CelK = elasticCel[i] + (K - Ki) / 0.5 * (elasticCel[i + 1] - elasticCel[i]) - } - else -> CelK = 0.0 - } - Delreturn = 2.0 * gam * gam * DH * (1.0 + sin(K * d) / (K * d)) * (1.0 + CelK) - } else { - theta = acos(c) * 180.0 / Math.PI - i = 0 - while (i <= 8) { - if (E >= elasticE[i] && E < elasticE[i + 1]) { - j = 0 - while (j <= 8) { - if (theta >= elasticT[j] && theta < elasticT[j + 1]) { - Delreturn = 1e-20 * (elasticD[i][j] + (elasticD[i][j + 1] - elasticD[i][j]) * (theta - elasticT[j]) / (elasticT[j + 1] - elasticT[j])) - } - j++ - } - } - i++ - } - } - return Delreturn - } - - private val excEE = 12.6 / 27.2 - private val excitationE = doubleArrayOf(0.0, 25.0, 35.0, 50.0, 100.0) - private val excitationT = doubleArrayOf(0.0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 180.0) - private val excitationD = arrayOf(doubleArrayOf(60.0, 43.0, 27.0, 18.0, 13.0, 8.0, 6.0, 6.0, 6.0), doubleArrayOf(95.0, 70.0, 21.0, 9.0, 6.0, 3.0, 2.0, 2.0, 2.0), doubleArrayOf(150.0, 120.0, 32.0, 8.0, 3.7, 1.9, 1.2, 0.8, 0.8), doubleArrayOf(400.0, 200.0, 12.0, 2.0, 1.4, 0.7, 0.3, 0.2, 0.2)) - - - private fun dExcitation(E: Double, c: Double): Double { - // This subroutine computes the differential cross section - // dElastic= d sigma/d Omega of excitation electron scattering - // on molecular hydrogen. - // Input: E= electron kinetic energy in eV - // c= cos(theta), where theta is the polar scatt. angle - // dExcitation: in m^2/steradian - var K2: Double - val K: Double - var sigma = 0.0 - val T: Double = E / 27.2 - val theta: Double - var i: Int - var j: Int - // - if (E >= 100.0) { - K2 = 4.0 * T * (1.0 - excEE / (2.0 * T) - sqrt(1.0 - excEE / T) * c) - if (K2 < 1e-9) { - K2 = 1e-9 - } - K = sqrt(K2) // momentum transfer - sigma = 2.0 / K2 * sumexc(K) * a02 - } else if (E <= 10.0) { - sigma = 0.0 - } else { - theta = acos(c) * 180.0 / Math.PI - i = 0 - while (i <= 3) { - if (E >= excitationE[i] && E < excitationE[i + 1]) { - j = 0 - while (j <= 7) { - if (theta >= excitationT[j] && theta < excitationT[j + 1]) { - sigma = 1e-22 * (excitationD[i][j] + (excitationD[i][j + 1] - excitationD[i][j]) * (theta - excitationT[j]) / (excitationT[j + 1] - excitationT[j])) - } - j++ - } - } - i++ - } - } - return sigma - } - - // This subroutine computes the differential cross section - // dInelastic= d sigma/d Omega of inelastic electron scattering - // on molecular hydrogen, within the first Born approximation. - // Input: E= electron kinetic energy in eV - // c= cos(theta), where theta is the polar scatt. angle - // dInelastic: in m2/steradian - private val cInelastic = doubleArrayOf(-0.246, -0.244, -0.239, -0.234, -0.227, -0.219, -0.211, -0.201, -0.190, -0.179, -0.167, -0.155, -0.142, -0.130, -0.118, -0.107, -0.096, -0.085, -0.076, -0.067, -0.059, -0.051, -0.045, -0.039, -0.034, -0.029, -0.025, -0.022, -0.019, -0.016, -0.014, -0.010, -0.008, -0.006, -0.004, -0.003, -0.003, -0.002, -0.002, -0.001, -0.001, -0.001, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000) - private val inelasticEi = 0.568 - - - private fun dInelastic(E: Double, c: Double): Double { - val T: Double = E / 27.2 - var K2: Double - val K: Double - val st1: Double - val F: Double - val DH: Double - val Dinelreturn: Double - val CinelK: Double - val Ki: Double - val i: Int - if (E < 16.0) { - return dExcitation(E, c) - } - K2 = 4.0 * T * (1.0 - inelasticEi / (2.0 * T) - sqrt(1.0 - inelasticEi / T) * c) - if (K2 < 1e-9) { - K2 = 1e-9 - } - K = sqrt(K2) // momentum transfer - st1 = 1.0 + K2 / 4.0 - F = 1.0 / (st1 * st1) // scatt. formfactor of hydrogen atom - // DH is the diff. cross section for inelastic electron scatt. - // on atomic hydrogen within the first Born approximation : - DH = 4.0 / (K2 * K2) * (1.0 - F * F) * a02 - // CinelK calculation with linear interpolation. - // CinelK is the correction of the inelastic electron - // scatt. on molecular hydrogen compared to the independent atom - // model. - if (K < 3.0) { - i = (K / 0.1).toInt() - Ki = i * 0.1 - CinelK = cInelastic[i] + (K - Ki) / 0.1 * (cInelastic[i + 1] - cInelastic[i]) - } else if (K >= 3.0 && K < 5.0) { - i = (30 + (K - 3.0) / 0.2).toInt() - Ki = 3.0 + (i - 30) * 0.2 - CinelK = cInelastic[i] + (K - Ki) / 0.2 * (cInelastic[i + 1] - cInelastic[i]) - } else if (K >= 5.0 && K < 9.49) { - i = (40 + (K - 5.0) / 0.5).toInt() - Ki = 5.0 + (i - 40) * 0.5 - CinelK = cInelastic[i] + (K - Ki) / 0.5 * (cInelastic[i + 1] - cInelastic[i]) - } else { - CinelK = 0.0 - } - Dinelreturn = 2.0 * DH * (1.0 + CinelK) - return Dinelreturn - } - - - private val sumexcKvec = doubleArrayOf(0.0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.5, 1.8, 2.0, 2.5, 3.0, 4.0, 5.0) - private val sumexcfvec = arrayOf( - doubleArrayOf(2.907e-1, 2.845e-1, 2.665e-1, 2.072e-1, 1.389e-1, - 8.238e-2, 4.454e-2, 2.269e-2, 7.789e-3, 2.619e-3, 1.273e-3, 2.218e-4, 4.372e-5, 2.889e-6, 4.247e-7), // B - doubleArrayOf(3.492e-1, 3.367e-1, 3.124e-1, 2.351e-1, 1.507e-1, - 8.406e-2, 4.214e-2, 1.966e-2, 5.799e-3, 1.632e-3, 6.929e-4, 8.082e-5, 9.574e-6, 1.526e-7, 7.058e-9), // C - doubleArrayOf(6.112e-2, 5.945e-2, 5.830e-2, 5.072e-2, 3.821e-2, - 2.579e-2, 1.567e-2, 8.737e-3, 3.305e-3, 1.191e-3, 6.011e-4, 1.132e-4, 2.362e-5, 1.603e-6, 2.215e-7), // Bp - doubleArrayOf(2.066e-2, 2.127e-2, 2.137e-2, 1.928e-2, 1.552e-2, - 1.108e-2, 7.058e-3, 4.069e-3, 1.590e-3, 5.900e-4, 3.046e-4, 6.142e-5, 1.369e-5, 9.650e-7, 1.244e-7), // Bpp - doubleArrayOf(9.405e-2, 9.049e-2, 8.613e-2, 7.301e-2, 5.144e-2, - 3.201e-2, 1.775e-2, 8.952e-3, 2.855e-3, 8.429e-4, 3.655e-4, 4.389e-5, 5.252e-6, 9.010e-8, 7.130e-9), // D - doubleArrayOf(4.273e-2, 3.862e-2, 3.985e-2, 3.362e-2, 2.486e-2, - 1.612e-2, 9.309e-3, 4.856e-3, 1.602e-3, 4.811e-4, 2.096e-4, 2.498e-5, 2.905e-6, 5.077e-8, 6.583e-9), // Dp - doubleArrayOf(0.000e-3, 2.042e-3, 7.439e-3, 2.200e-2, 3.164e-2, - 3.161e-2, 2.486e-2, 1.664e-2, 7.562e-3, 3.044e-3, 1.608e-3, 3.225e-4, 7.120e-5, 6.290e-6, 1.066e-6))// EF - private val sumexcEeV = doubleArrayOf(12.73, 13.20, 14.77, 15.3, 14.93, 15.4, 13.06) - - private fun _sumexc(K: Double): Double { - var n: Int = 0 - var j: Int - var jmin = 0 - val nmax: Int = 6 - var En: Double - var sum: Double = 0.0 - val f = DoubleArray(7) - val x4 = DoubleArray(4) - val f4 = DoubleArray(4) - - // - while (n <= nmax) { - En = sumexcEeV[n] / 27.21 // En is the excitation energy in Hartree atomic units - when { - K >= 5.0 -> f[n] = 0.0 - K in 3.0..4.0 -> f[n] = sumexcfvec[n][12] + (K - 3.0) * (sumexcfvec[n][13] - sumexcfvec[n][12]) - K in 4.0..5.0 -> f[n] = sumexcfvec[n][13] + (K - 4.0) * (sumexcfvec[n][14] - sumexcfvec[n][13]) - else -> { - j = 0 - while (j < 14) { - if (K >= sumexcKvec[j] && K <= sumexcKvec[j + 1]) { - jmin = j - 1 - } - j++ - } - if (jmin < 0) { - jmin = 0 - } - if (jmin > 11) { - jmin = 11 - } - j = 0 - while (j <= 3) { - x4[j] = sumexcKvec[jmin + j] - f4[j] = sumexcfvec[n][jmin + j] - j++ - } - f[n] = lagrange(4, x4, f4, K) - } - } - sum += f[n] / En - n++ - } - return sum - } - - //Caching function for precision - private val sumexcCache = FunctionCache(0.01, this::_sumexc) - - private fun sumexc(K: Double): Double = sumexcCache(K) - - private fun lagrange(n: Int, xn: DoubleArray, fn: DoubleArray, x: Double): Double { - var i: Int - var j: Int = 0 - var f: Double = 0.0 - var aa: Double - var bb: Double - val a = DoubleArray(100) - val b = DoubleArray(100) - while (j < n) { - i = 0 - while (i < n) { - a[i] = x - xn[i] - b[i] = xn[j] - xn[i] - i++ - } - bb = 1.0 - aa = bb - b[j] = aa - a[j] = b[j] - i = 0 - while (i < n) { - aa *= a[i] - bb *= b[i] - i++ - } - f += fn[j] * aa / bb - j++ - } - return f - } - - // This function computes the total elastic cross section of - // electron scatt. on molecular hydrogen. - // See: Liu, Phys. Rev. A35 (1987) 591, - // Trajmar, Phys Reports 97 (1983) 221. - // E: incident electron energy in eV - // sigmael: cross section in m^2 - private val sigmaelE = doubleArrayOf(0.0, 1.5, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 60.0, 100.0, 150.0, 200.0, 300.0, 400.0) - private val sigmaelS = doubleArrayOf(9.6, 13.0, 15.0, 12.0, 10.0, 7.0, 5.6, 3.3, 1.1, 0.9, 0.5, 0.36, 0.23, 0.15) - - fun sigmael(E: Double): Double { - val gam: Double - var sigma = 0.0 - val T: Double = E / 27.2 - var i: Int - if (E >= 400.0) { - gam = (emass + T) / emass - sigma = gam * gam * Math.PI / (2.0 * T) * (4.2106 - 1.0 / T) * a02 - } else { - i = 0 - while (i <= 12) { - if (E >= sigmaelE[i] && E < sigmaelE[i + 1]) { - sigma = 1e-20 * (sigmaelS[i] + (sigmaelS[i + 1] - sigmaelS[i]) * (E - sigmaelE[i]) / (sigmaelE[i + 1] - sigmaelE[i])) - } - i++ - } - } - return sigma - } - - fun sigmaexc(E: Double): Double { - // This function computes the electronic excitation cross section of - // electron scatt. on molecular hydrogen. - // E: incident electron energy in eV, - // sigmaexc: cross section in m^2 - return when { - E < 9.8 -> 1e-40 - E in 9.8..250.0 -> sigmaBC(E) + sigmadiss10(E) + sigmadiss15(E) - else -> 4.0 * Math.PI * a02 * R / E * (0.80 * log(E / R) + 0.28) - } - // sigma=sigmainel(E)-sigmaion(E); - } - - fun sigmaion(E: Double): Double { - // This function computes the total ionization cross section of - // electron scatt. on molecular hydrogen. - // E: incident electron energy in eV, - // sigmaion: total ionization cross section of - // e+H2 --> e+e+H2^+ or e+e+H^+ +H - // process in m^2. - // - // E<250 eV: Eq. 5 of J. Chem. Phys. 104 (1996) 2956 - // E>250: sigma_i formula on page 107 in - // Phys. Rev. A7 (1973) 103. - // Good agreement with measured results of - // PR A 54 (1996) 2146, and - // Physica 31 (1965) 94. - // - val B = 15.43 - val U = 15.98 - val sigma: Double - val t: Double - val u: Double - val S: Double - val r: Double - val lnt: Double - if (E < 16.0) { - sigma = 1e-40 - } else if (E >= 16.0 && E <= 250.0) { - t = E / B - u = U / B - r = R / B - S = 4.0 * Math.PI * a02 * 2.0 * r * r - lnt = log(t) - sigma = S / (t + u + 1.0) * (lnt / 2.0 * (1.0 - 1.0 / (t * t)) + 1.0 - 1.0 / t - lnt / (t + 1.0)) - } else { - sigma = 4.0 * Math.PI * a02 * R / E * (0.82 * log(E / R) + 1.3) - } - return sigma - } - - // This function computes the sigmaexc electronic excitation - // cross section to the B and C states, with energy loss - // about 12.5 eV. - // E is incident electron energy in eV, - // sigmaexc in m^2 - private val aB = doubleArrayOf(-4.2935194e2, 5.1122109e2, -2.8481279e2, 8.8310338e1, -1.6659591e1, 1.9579609, -1.4012824e-1, 5.5911348e-3, -9.5370103e-5) - private val aC = doubleArrayOf(-8.1942684e2, 9.8705099e2, -5.3095543e2, 1.5917023e2, -2.9121036e1, 3.3321027, -2.3305961e-1, 9.1191781e-3, -1.5298950e-4) - - private fun sigmaBC(E: Double): Double { - var lnsigma: Double = 0.0 - var lnE: Double = log(E) - var lnEn: Double = 1.0 - val sigmaB: Double - var Emin: Double = 12.5 - var sigma: Double = 0.0 - val sigmaC: Double - var n: Int - if (E < Emin) { - sigmaB = 0.0 - } else { - n = 0 - while (n <= 8) { - lnsigma += aB[n] * lnEn - lnEn *= lnE - n++ - } - sigmaB = exp(lnsigma) - } - sigma += sigmaB - // sigma=0.; - // C state: - Emin = 15.8 - lnE = log(E) - lnEn = 1.0 - lnsigma = 0.0 - if (E < Emin) { - sigmaC = 0.0 - } else { - n = 0 - while (n <= 8) { - lnsigma += aC[n] * lnEn - lnEn *= lnE - n++ - } - sigmaC = exp(lnsigma) - } - sigma += sigmaC - return sigma * 1e-4 - } - - ////////////////////////////////////////////////////////////////// - - // This function computes the sigmadiss10 electronic - // dissociative excitation - // cross section, with energy loss - // about 10 eV. - // E is incident electron energy in eV, - // sigmadiss10 in m^2 - private val sigmadiss10a = doubleArrayOf(-2.297914361e5, 5.303988579e5, -5.316636672e5, 3.022690779e5, -1.066224144e5, 2.389841369e4, -3.324526406e3, 2.624761592e2, -9.006246604) - - private fun sigmadiss10(E: Double): Double { - var lnsigma: Double = 0.0 - val lnE: Double = log(E) - var lnEn: Double = 1.0 - val Emin = 9.8 - var n: Int - // E is in eV - val sigma = if (E < Emin) { - 0.0 - } else { - n = 0 - while (n <= 8) { - lnsigma += sigmadiss10a[n] * lnEn - lnEn *= lnE - n++ - } - exp(lnsigma) - } - return sigma * 1e-4 - } - - ////////////////////////////////////////////////////////////////// - // This function computes the sigmadiss15 electronic - // dissociative excitation - // cross section, with energy loss - // about 15 eV. - // E is incident electron energy in eV, - // sigmadiss15 in m^2 - private val sigmadiss15a = doubleArrayOf(-1.157041752e3, 1.501936271e3, -8.6119387e2, 2.754926257e2, -5.380465012e1, 6.573972423, -4.912318139e-1, 2.054926773e-2, -3.689035889e-4) - - private fun sigmadiss15(E: Double): Double { - var lnsigma: Double = 0.0 - val lnE: Double = log(E) - var lnEn: Double - val Emin: Double = 16.5 - var n: Int - // E is in eV - lnEn = 1.0 - val sigma = if (E < Emin) { - 0.0 - } else { - n = 0 - while (n <= 8) { - lnsigma += sigmadiss15a[n] * lnEn - lnEn *= lnE - n++ - } - exp(lnsigma) - } - return sigma * 1e-4 - } - - /** - * Полное сечение с учетом квазиупругих столкновений - * - * @param E - * @return - */ - fun sigmaTotal(E: Double): Double { - return sigmael(E) + sigmaexc(E) + sigmaion(E) - - } -} +package ru.inr.mass.trapping + +import org.apache.commons.math3.random.RandomGenerator +import org.apache.commons.math3.util.FastMath.* +import org.apache.commons.math3.util.Pair + +/** + * + * The initial code was written by Ferenc Glueck and then rewritten by [Sebastian Voecking](mailto:seb.voeck@uni-muenster.de) + * into C++. To reference the code, don't forget to also include [kasiopea](http://stacks.iop.org/1367-2630/19/i=5/a=053012). + * @author Darksnake + */ +object Scatter { + + var debug = false + + val counter = MultiCounter("Accept-reject calls") + + + private val a02 = 28e-22 // Bohr radius squared + private val clight = 137.0 // velocity of light in atomic units + private val emass = 18780.0 // Electron mass in atomic units + private val R = 13.6 // Ryberg energy in eV + + private fun count(counterName: String) { + if (debug) { + counter.increase(counterName) + } + } + + fun randomel(E: Double, generator: RandomGenerator): Pair { + // This subroutine generates energy loss and polar scatt. angle according to + // electron elastic scattering in molecular hydrogen. + // Input: + // E: incident electron energy in eV. + // Output: + // *Eloss: energy loss in eV + // *theta: change of polar angle in degrees + val H2molmass = 69e6 + val T: Double = E / 27.2 + var c = 1.0 + val b: Double + var G: Double + var a: Double + val gam: Double + var K2: Double + val Gmax: Double = when { + E >= 250.0 -> 1e-19 + E < 250.0 && E >= 150.0 -> 2.5e-19 + else -> 1e-18 + } + var i: Int = 1 + + count("randomel-calls") + gam = 1.0 + T / (clight * clight) // relativistic correction factor + b = 2.0 / (1.0 + gam) / T + while (i < 5000) { + count("randomel") + c = 1.0 + b - b * (2.0 + b) / (b + 2.0 * generator.nextDouble()) + K2 = 2.0 * T * (1.0 + gam) * abs(1.0 - c) // momentum transfer squared + a = (4.0 + K2) * (4.0 + K2) / (gam * gam) + G = a * dElastic(E, c) + if (G > Gmax * generator.nextDouble()) { + break + } + i++ + } + return Pair(2.0 * emass / H2molmass * (1.0 - c) * E, acos(c) * 180.0 / Math.PI) + } + + + // Energy values of the excited electronic states: + // (from Mol. Phys. 41 (1980) 1501, in Hartree atomic units) + private val En = doubleArrayOf(12.73 / 27.2, 13.2 / 27.2, 14.77 / 27.2, 15.3 / 27.2, 14.93 / 27.2, 15.4 / 27.2, 13.06 / 27.2) + // Probability numbers of the electronic states: + // (from testelectron7.c calculation ) + private val p = doubleArrayOf(35.86, 40.05, 6.58, 2.26, 9.61, 4.08, 1.54) + // Energy values of the B vibrational states: + // (from: Phys. Rev. A51 (1995) 3745 , in Hartree atomic units) + private val EB = doubleArrayOf(0.411, 0.417, 0.423, 0.428, 0.434, 0.439, 0.444, 0.449, 0.454, 0.459, 0.464, 0.468, 0.473, 0.477, 0.481, 0.485, 0.489, 0.493, 0.496, 0.500, 0.503, 0.507, 0.510, 0.513, 0.516, 0.519, 0.521, 0.524) + // Energy values of the C vibrational states: + // (from: Phys. Rev. A51 (1995) 3745 , in Hartree atomic units) + private val EC = doubleArrayOf(0.452, 0.462, 0.472, 0.481, 0.490, 0.498, 0.506, 0.513, 0.519, 0.525, 0.530, 0.534, 0.537, 0.539) + // Franck-Condon factors of the B vibrational states: + // (from: Phys. Rev. A51 (1995) 3745 ) + private val pB = doubleArrayOf(4.2e-3, 1.5e-2, 3.0e-2, 4.7e-2, 6.3e-2, 7.3e-2, 7.9e-2, 8.0e-2, 7.8e-2, 7.3e-2, 6.6e-2, 5.8e-2, 5.1e-2, 4.4e-2, 3.7e-2, 3.1e-2, 2.6e-2, 2.2e-2, 1.8e-2, 1.5e-2, 1.3e-2, 1.1e-2, 8.9e-3, 7.4e-3, 6.2e-3, 5.2e-3, 4.3e-3, 3.6e-3) + // Franck-Condon factors of the C vibrational states: + // (from: Phys. Rev. A51 (1995) 3745 ) + private val pC = doubleArrayOf(1.2e-1, 1.9e-1, 1.9e-1, 1.5e-1, 1.1e-1, 7.5e-2, 5.0e-2, 3.3e-2, 2.2e-2, 1.4e-2, 9.3e-3, 6.0e-3, 3.7e-3, 1.8e-3) + + private val Ecen = 12.6 / 27.21 + + private val fmax by lazy { + val sum = DoubleArray(1001) + + val T: Double = 20000.0 / 27.2 + val xmin = Ecen * Ecen / (2.0 * T) + val ymin = log(xmin) + val ymax = log(8.0 * T + xmin) + val dy = (ymax - ymin) / 1000.0 + + + var res = 0.0 + var i = 0 + while (i <= 1000) { + val y = ymin + dy * i + val K = exp(y / 2.0) + sum[i] = sumexc(K) + if (sum[i] > res) { + res = sum[i] + } + i++ + } + res *= 1.05 + res + } + + + fun randomexc(E: Double, generator: RandomGenerator): Pair { + // This subroutine generates energy loss and polar scatt. angle according to + // electron excitation scattering in molecular hydrogen. + // Input: + // E: incident electron energy in eV. + // Output: + // *Eloss: energy loss in eV + // *theta: change of polar angle in degrees + + + var c = 0.0 + var K: Double + var y: Double + var fy: Double + var pmax: Double + var D: Double + var j: Int + var n = 0 + var N: Int + var v = 0 + + count("randomexc-calls") + + // + // Scattering angle *theta generation: + // + val T = E / 27.2 + val theta: Double + if (E >= 100.0) { + val xmin = Ecen * Ecen / (2.0 * T) + val ymin = log(xmin) + val ymax = log(8.0 * T + xmin) + // dy = (ymax - ymin) / 1000.; + // Generation of y values with the Neumann acceptance-rejection method: + y = ymin + j = 1 + while (j < 5000) { + count("randomexc1") + y = ymin + (ymax - ymin) * generator.nextDouble() + K = exp(y / 2.0) + fy = sumexc(K) + if (fmax * generator.nextDouble() < fy) { + break + } + j++ + } + // Calculation of c=cos(theta) and theta: + val x = exp(y) + c = 1.0 - (x - xmin) / (4.0 * T) + theta = acos(c) * 180.0 / Math.PI + } else { + val Dmax = when { + E <= 25.0 -> 60.0 + E > 25.0 && E <= 35.0 -> 95.0 + E > 35.0 && E <= 50.0 -> 150.0 + else -> 400.0 + } + j = 1 + + while (j < 5000) { + count("randomexc2") + c = -1.0 + 2.0 * generator.nextDouble() + D = dExcitation(E, c) * 1e22 + if (Dmax * generator.nextDouble() < D) { + break + } + j++ + } + theta = acos(c) * 180.0 / Math.PI + } + // Energy loss *Eloss generation: + + // First we generate the electronic state, using the Neumann + // acceptance-rejection method for discrete distribution: + N = 7 // the number of electronic states in our calculation + pmax = p[1] // the maximum of the p[] values + j = 1 + while (j < 5000) { + count("randomexc3") + n = (N * generator.nextDouble()).toInt() + if (generator.nextDouble() * pmax < p[n]) { + break + } + j++ + }// Bp, Bpp, D, Dp, EF states + // C state; we generate now a vibrational state, + // using the Franck-Condon factors + // the number of C vibrational states in our calculation + // maximum of the pC[] values + // B state; we generate now a vibrational state, + // using the Frank-Condon factors + // the number of B vibrational states in our calculation + // maximum of the pB[] values + when { + n < 0 -> n = 0 + n > 6 -> n = 6 + } + val Eloss: Double + when (n) { + 0 -> { + // B state; we generate now a vibrational state, + // using the Frank-Condon factors + N = 28 // the number of B vibrational states in our calculation + pmax = pB[7] // maximum of the pB[] values + j = 1 + while (j < 5000) { + count("randomexc4") + v = (N * generator.nextDouble()).toInt() + if (generator.nextDouble() * pmax < pB[v]) { + break + } + j++ + } + if (v < 0) { + v = 0 + } + if (v > 27) { + v = 27 + } + Eloss = EB[v] * 27.2 + } + 1 -> { + // C state; we generate now a vibrational state, + // using the Franck-Condon factors + N = 14 // the number of C vibrational states in our calculation + pmax = pC[1] // maximum of the pC[] values + j = 1 + while (j < 5000) { + count("randomexc4") + v = (N * generator.nextDouble()).toInt() + if (generator.nextDouble() * pmax < pC[v]) { + break + } + j++ + } + if (v < 0) { + v = 0 + } + if (v > 13) { + v = 13 + } + Eloss = EC[v] * 27.2 + } + else -> + // Bp, Bpp, D, Dp, EF states + Eloss = En[n] * 27.2 + } + return Pair(Eloss, theta) + } + + fun randomion(E: Double, generator: RandomGenerator): Pair { + // This subroutine generates energy loss and polar scatt. angle according to + // electron ionization scattering in molecular hydrogen. + // Input: + // E: incident electron energy in eV. + // Output: + // *Eloss: energy loss in eV + // *theta: change of polar angle in degrees + // The kinetic energy of the secondary electron is: Eloss-15.4 eV + // + val Ei = 15.45 / 27.21 + var c: Double + val b: Double + var K: Double + val xmin: Double + val ymin: Double + val ymax: Double + val x: Double + var y: Double + val T: Double = E / 27.2 + var G: Double + var Gmax: Double + var q: Double + val h: Double + var F: Double + val Fmin: Double + val Fmax: Double + var Gp: Double + val Elmin: Double + val Elmax: Double = (E + 15.45) / 2.0 / 27.2 + val qmin: Double + val qmax: Double + var El: Double + val wmax: Double + var WcE: Double + var Jstarq: Double + var WcstarE: Double + var w: Double + var D2ion: Double + var j: Int = 1 + var K2: Double + var KK: Double + var fE: Double + var kej: Double + var ki: Double + var kf: Double + var Rex: Double + var arg: Double + var arctg: Double + var i: Int + var st1: Double + var st2: Double + count("randomion-calls") + // + // I. Generation of theta + // ----------------------- + Gmax = 1e-20 + if (E < 200.0) { + Gmax = 2e-20 + } + xmin = Ei * Ei / (2.0 * T) + b = xmin / (4.0 * T) + ymin = log(xmin) + ymax = log(8.0 * T + xmin) + // Generation of y values with the Neumann acceptance-rejection method: + y = ymin + while (j < 5000) { + count("randomion1") + y = ymin + (ymax - ymin) * generator.nextDouble() + K = exp(y / 2.0) + c = 1.0 + b - K * K / (4.0 * T) + G = K * K * (dInelastic(E, c) - dExcitation(E, c)) + if (Gmax * generator.nextDouble() < G) { + break + } + j++ + } + // y --> x --> c --> theta + x = exp(y) + c = 1.0 - (x - xmin) / (4.0 * T) + val theta = acos(c) * 180.0 / Math.PI + // + // II. Generation of Eloss, for fixed theta + // ---------------------------------------- + // + // For E<=100 eV we use subr. gensecelen + // (in this case no correlation between theta and Eloss) + if (E <= 100.0) { + return Pair(15.45 + gensecelen(E, generator), theta) + } + // For theta>=20 the free electron model is used + // (with full correlation between theta and Eloss) + if (theta >= 20.0) { + return Pair(E * (1.0 - c * c), theta) + } + // For E>100 eV and theta<20: analytical first Born approximation + // formula of Bethe for H atom (with modification for H2) + // + // Calc. of wmax: + if (theta >= 0.7) { + wmax = 1.1 + } else if (theta <= 0.7 && theta > 0.2) { + wmax = 2.0 + } else if (theta <= 0.2 && theta > 0.05) { + wmax = 4.0 + } else { + wmax = 8.0 + } + // We generate the q value according to the Jstarq pdf. We have to + // define the qmin and qmax limits for this generation: + K = sqrt(4.0 * T * (1.0 - Ei / (2.0 * T) - sqrt(1.0 - Ei / T) * c)) + Elmin = Ei + qmin = Elmin / K - K / 2.0 + qmax = Elmax / K - K / 2.0 + // + q = qmax + Fmax = 1.0 / 2.0 + 1.0 / Math.PI * (q / (1.0 + q * q) + atan(q)) + q = qmin + Fmin = 1.0 / 2.0 + 1.0 / Math.PI * (q / (1.0 + q * q) + atan(q)) + h = Fmax - Fmin + // Generation of Eloss with the Neumann acceptance-rejection method: + El = 0.0 + j = 1 + while (j < 5000) { + // Generation of q with inverse transform method + // (we use the Newton-Raphson method in order to solve the nonlinear eq. + // for the inversion) : + count("randomion2") + F = Fmin + h * generator.nextDouble() + y = 0.0 + i = 1 + while (i <= 30) { + G = 1.0 / 2.0 + (y + sin(2.0 * y) / 2.0) / Math.PI + Gp = (1.0 + cos(2.0 * y)) / Math.PI + y -= (G - F) / Gp + if (abs(G - F) < 1e-8) { + break + } + i++ + } + q = tan(y) + // We have the q value, so we can define El, and calculate the weight: + El = q * K + K * K / 2.0 + // First Born approximation formula of Bethe for e-H ionization: + KK = K + ki = sqrt(2.0 * T) + kf = sqrt(2.0 * (T - El)) + K2 = 4.0 * T * (1.0 - El / (2.0 * T) - sqrt(1.0 - El / T) * c) + if (K2 < 1e-9) { + K2 = 1e-9 + } + K = sqrt(K2) // momentum transfer + Rex = 1.0 - K * K / (kf * kf) + K2 * K2 / (kf * kf * kf * kf) + kej = sqrt(2.0 * abs(El - Ei) + 1e-8) + st1 = K2 - 2.0 * El + 2.0 + if (abs(st1) < 1e-9) { + st1 = 1e-9 + } + arg = 2.0 * kej / st1 + arctg = if (arg >= 0.0) { + atan(arg) + } else { + atan(arg) + Math.PI + } + st1 = (K + kej) * (K + kej) + 1.0 + st2 = (K - kej) * (K - kej) + 1.0 + fE = 1024.0 * El * (K2 + 2.0 / 3.0 * El) / (st1 * st1 * st1 * st2 * st2 * st2) * exp(-2.0 / kej * arctg) / (1.0 - exp(-2.0 * Math.PI / kej)) + D2ion = 2.0 * kf / ki * Rex / (El * K2) * fE + K = KK + // + WcE = D2ion + Jstarq = 16.0 / (3.0 * Math.PI * (1.0 + q * q) * (1.0 + q * q)) + WcstarE = 4.0 / (K * K * K * K * K) * Jstarq + w = WcE / WcstarE + if (wmax * generator.nextDouble() < w) { + break + } + j++ + } + + return Pair(El * 27.2, theta) + } + + private fun gensecelen(E: Double, generator: RandomGenerator): Double { + // This subroutine generates secondary electron energy W + // from ionization of incident electron energy E, by using + // the Lorentzian of Aseev et al. (Eq. 8). + // E and W in eV. + val Ei = 15.45 + val eps2 = 14.3 + val b = 6.25 + val B: Double = atan((Ei - eps2) / b) + val D: Double + val A: Double + val eps: Double + val a: Double + val u: Double = generator.nextDouble() + val epsmax: Double + + epsmax = (E + Ei) / 2.0 + A = atan((epsmax - eps2) / b) + D = b / (A - B) + a = b / D * (u + D / b * B) + eps = eps2 + b * tan(a) + return eps - Ei + } + + + // This subroutine computes the differential cross section + // dElastic= d sigma/d Omega of elastic electron scattering + // on molecular hydrogen. + // See: Nishimura et al., J. Phys. Soc. Jpn. 54 (1985) 1757. + // Input: E= electron kinetic energy in eV + // c= cos(theta), where theta is the polar scatt. angle + // dElastic: in m^2/steradian + private val elasticCel = doubleArrayOf(-0.512, -0.512, -0.509, -0.505, -0.499, -0.491, -0.476, -0.473, -0.462, -0.452, -0.438, -0.422, -0.406, -0.388, -0.370, -0.352, -0.333, -0.314, -0.296, -0.277, -0.258, -0.239, -0.221, -0.202, -0.185, -0.167, -0.151, -0.135, -0.120, -0.105, -0.092, -0.070, -0.053, -0.039, -0.030, -0.024, -0.019, -0.016, -0.014, -0.013, -0.012, -0.009, -0.008, -0.006, -0.005, -0.004, -0.003, -0.002, -0.002, -0.001) + private val elasticE = doubleArrayOf(0.0, 3.0, 6.0, 12.0, 20.0, 32.0, 55.0, 85.0, 150.0, 250.0) + private val elasticT = doubleArrayOf(0.0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 140.0, 180.0) + private val elasticD = arrayOf( + doubleArrayOf(2.9, 2.7, 2.5, 2.1, 1.8, 1.2, 0.9, 1.0, 1.6, 1.9), + doubleArrayOf(4.2, 3.6, 3.1, 2.5, 1.9, 1.1, 0.8, 0.9, 1.3, 1.4), + doubleArrayOf(6.0, 4.4, 3.2, 2.3, 1.8, 1.1, 0.7, 0.54, 0.5, 0.6), + doubleArrayOf(6.0, 4.1, 2.8, 1.9, 1.3, 0.6, 0.3, 0.17, 0.16, 0.23), + doubleArrayOf(4.9, 3.2, 2.0, 1.2, 0.8, 0.3, 0.15, 0.09, 0.05, 0.05), + doubleArrayOf(5.2, 2.5, 1.2, 0.64, 0.36, 0.13, 0.05, 0.03, 0.016, 0.02), + doubleArrayOf(4.0, 1.7, 0.7, 0.3, 0.16, 0.05, 0.02, 0.013, 0.01, 0.01), + doubleArrayOf(2.8, 1.1, 0.4, 0.15, 0.07, 0.02, 0.01, 0.007, 0.004, 0.003), + doubleArrayOf(1.2, 0.53, 0.2, 0.08, 0.03, 0.0074, 0.003, 0.0016, 0.001, 0.0008) + ) + + + private fun dElastic(E: Double, c: Double): Double { + val T: Double = E / 27.2 + var K2: Double + var K: Double + val d: Double + val st1: Double + val st2: Double + val DH: Double + val gam: Double + var Delreturn = 0.0 + val CelK: Double + val Ki: Double + val theta: Double + var i: Int + var j: Int + if (E >= 250.0) { + gam = 1.0 + T / (clight * clight) // relativistic correction factor + K2 = 2.0 * T * (1.0 + gam) * (1.0 - c) + if (K2 < 0.0) { + K2 = 1e-30 + } + K = sqrt(K2) + if (K < 1e-9) { + K = 1e-9 // momentum transfer + } + d = 1.4009 // distance of protons in H2 + st1 = 8.0 + K2 + st2 = 4.0 + K2 + // DH is the diff. cross section for elastic electron scatt. + // on atomic hydrogen within the first Born approximation : + DH = 4.0 * st1 * st1 / (st2 * st2 * st2 * st2) * a02 + // CelK calculation with linear interpolation. + // CelK is the correction of the elastic electron + // scatt. on molecular hydrogen compared to the independent atom + // model. + when { + K < 3.0 -> { + i = (K / 0.1).toInt() + Ki = i * 0.1 + CelK = elasticCel[i] + (K - Ki) / 0.1 * (elasticCel[i + 1] - elasticCel[i]) + } + K >= 3.0 && K < 5.0 -> { + i = (30 + (K - 3.0) / 0.2).toInt() + Ki = 3.0 + (i - 30) * 0.2 + CelK = elasticCel[i] + (K - Ki) / 0.2 * (elasticCel[i + 1] - elasticCel[i]) + } + K >= 5.0 && K < 9.49 -> { + i = (40 + (K - 5.0) / 0.5).toInt() + Ki = 5.0 + (i - 40) * 0.5 + CelK = elasticCel[i] + (K - Ki) / 0.5 * (elasticCel[i + 1] - elasticCel[i]) + } + else -> CelK = 0.0 + } + Delreturn = 2.0 * gam * gam * DH * (1.0 + sin(K * d) / (K * d)) * (1.0 + CelK) + } else { + theta = acos(c) * 180.0 / Math.PI + i = 0 + while (i <= 8) { + if (E >= elasticE[i] && E < elasticE[i + 1]) { + j = 0 + while (j <= 8) { + if (theta >= elasticT[j] && theta < elasticT[j + 1]) { + Delreturn = 1e-20 * (elasticD[i][j] + (elasticD[i][j + 1] - elasticD[i][j]) * (theta - elasticT[j]) / (elasticT[j + 1] - elasticT[j])) + } + j++ + } + } + i++ + } + } + return Delreturn + } + + private val excEE = 12.6 / 27.2 + private val excitationE = doubleArrayOf(0.0, 25.0, 35.0, 50.0, 100.0) + private val excitationT = doubleArrayOf(0.0, 10.0, 20.0, 30.0, 40.0, 60.0, 80.0, 100.0, 180.0) + private val excitationD = arrayOf(doubleArrayOf(60.0, 43.0, 27.0, 18.0, 13.0, 8.0, 6.0, 6.0, 6.0), doubleArrayOf(95.0, 70.0, 21.0, 9.0, 6.0, 3.0, 2.0, 2.0, 2.0), doubleArrayOf(150.0, 120.0, 32.0, 8.0, 3.7, 1.9, 1.2, 0.8, 0.8), doubleArrayOf(400.0, 200.0, 12.0, 2.0, 1.4, 0.7, 0.3, 0.2, 0.2)) + + + private fun dExcitation(E: Double, c: Double): Double { + // This subroutine computes the differential cross section + // dElastic= d sigma/d Omega of excitation electron scattering + // on molecular hydrogen. + // Input: E= electron kinetic energy in eV + // c= cos(theta), where theta is the polar scatt. angle + // dExcitation: in m^2/steradian + var K2: Double + val K: Double + var sigma = 0.0 + val T: Double = E / 27.2 + val theta: Double + var i: Int + var j: Int + // + if (E >= 100.0) { + K2 = 4.0 * T * (1.0 - excEE / (2.0 * T) - sqrt(1.0 - excEE / T) * c) + if (K2 < 1e-9) { + K2 = 1e-9 + } + K = sqrt(K2) // momentum transfer + sigma = 2.0 / K2 * sumexc(K) * a02 + } else if (E <= 10.0) { + sigma = 0.0 + } else { + theta = acos(c) * 180.0 / Math.PI + i = 0 + while (i <= 3) { + if (E >= excitationE[i] && E < excitationE[i + 1]) { + j = 0 + while (j <= 7) { + if (theta >= excitationT[j] && theta < excitationT[j + 1]) { + sigma = 1e-22 * (excitationD[i][j] + (excitationD[i][j + 1] - excitationD[i][j]) * (theta - excitationT[j]) / (excitationT[j + 1] - excitationT[j])) + } + j++ + } + } + i++ + } + } + return sigma + } + + // This subroutine computes the differential cross section + // dInelastic= d sigma/d Omega of inelastic electron scattering + // on molecular hydrogen, within the first Born approximation. + // Input: E= electron kinetic energy in eV + // c= cos(theta), where theta is the polar scatt. angle + // dInelastic: in m2/steradian + private val cInelastic = doubleArrayOf(-0.246, -0.244, -0.239, -0.234, -0.227, -0.219, -0.211, -0.201, -0.190, -0.179, -0.167, -0.155, -0.142, -0.130, -0.118, -0.107, -0.096, -0.085, -0.076, -0.067, -0.059, -0.051, -0.045, -0.039, -0.034, -0.029, -0.025, -0.022, -0.019, -0.016, -0.014, -0.010, -0.008, -0.006, -0.004, -0.003, -0.003, -0.002, -0.002, -0.001, -0.001, -0.001, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000) + private val inelasticEi = 0.568 + + + private fun dInelastic(E: Double, c: Double): Double { + val T: Double = E / 27.2 + var K2: Double + val K: Double + val st1: Double + val F: Double + val DH: Double + val Dinelreturn: Double + val CinelK: Double + val Ki: Double + val i: Int + if (E < 16.0) { + return dExcitation(E, c) + } + K2 = 4.0 * T * (1.0 - inelasticEi / (2.0 * T) - sqrt(1.0 - inelasticEi / T) * c) + if (K2 < 1e-9) { + K2 = 1e-9 + } + K = sqrt(K2) // momentum transfer + st1 = 1.0 + K2 / 4.0 + F = 1.0 / (st1 * st1) // scatt. formfactor of hydrogen atom + // DH is the diff. cross section for inelastic electron scatt. + // on atomic hydrogen within the first Born approximation : + DH = 4.0 / (K2 * K2) * (1.0 - F * F) * a02 + // CinelK calculation with linear interpolation. + // CinelK is the correction of the inelastic electron + // scatt. on molecular hydrogen compared to the independent atom + // model. + if (K < 3.0) { + i = (K / 0.1).toInt() + Ki = i * 0.1 + CinelK = cInelastic[i] + (K - Ki) / 0.1 * (cInelastic[i + 1] - cInelastic[i]) + } else if (K >= 3.0 && K < 5.0) { + i = (30 + (K - 3.0) / 0.2).toInt() + Ki = 3.0 + (i - 30) * 0.2 + CinelK = cInelastic[i] + (K - Ki) / 0.2 * (cInelastic[i + 1] - cInelastic[i]) + } else if (K >= 5.0 && K < 9.49) { + i = (40 + (K - 5.0) / 0.5).toInt() + Ki = 5.0 + (i - 40) * 0.5 + CinelK = cInelastic[i] + (K - Ki) / 0.5 * (cInelastic[i + 1] - cInelastic[i]) + } else { + CinelK = 0.0 + } + Dinelreturn = 2.0 * DH * (1.0 + CinelK) + return Dinelreturn + } + + + private val sumexcKvec = doubleArrayOf(0.0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.5, 1.8, 2.0, 2.5, 3.0, 4.0, 5.0) + private val sumexcfvec = arrayOf( + doubleArrayOf(2.907e-1, 2.845e-1, 2.665e-1, 2.072e-1, 1.389e-1, + 8.238e-2, 4.454e-2, 2.269e-2, 7.789e-3, 2.619e-3, 1.273e-3, 2.218e-4, 4.372e-5, 2.889e-6, 4.247e-7), // B + doubleArrayOf(3.492e-1, 3.367e-1, 3.124e-1, 2.351e-1, 1.507e-1, + 8.406e-2, 4.214e-2, 1.966e-2, 5.799e-3, 1.632e-3, 6.929e-4, 8.082e-5, 9.574e-6, 1.526e-7, 7.058e-9), // C + doubleArrayOf(6.112e-2, 5.945e-2, 5.830e-2, 5.072e-2, 3.821e-2, + 2.579e-2, 1.567e-2, 8.737e-3, 3.305e-3, 1.191e-3, 6.011e-4, 1.132e-4, 2.362e-5, 1.603e-6, 2.215e-7), // Bp + doubleArrayOf(2.066e-2, 2.127e-2, 2.137e-2, 1.928e-2, 1.552e-2, + 1.108e-2, 7.058e-3, 4.069e-3, 1.590e-3, 5.900e-4, 3.046e-4, 6.142e-5, 1.369e-5, 9.650e-7, 1.244e-7), // Bpp + doubleArrayOf(9.405e-2, 9.049e-2, 8.613e-2, 7.301e-2, 5.144e-2, + 3.201e-2, 1.775e-2, 8.952e-3, 2.855e-3, 8.429e-4, 3.655e-4, 4.389e-5, 5.252e-6, 9.010e-8, 7.130e-9), // D + doubleArrayOf(4.273e-2, 3.862e-2, 3.985e-2, 3.362e-2, 2.486e-2, + 1.612e-2, 9.309e-3, 4.856e-3, 1.602e-3, 4.811e-4, 2.096e-4, 2.498e-5, 2.905e-6, 5.077e-8, 6.583e-9), // Dp + doubleArrayOf(0.000e-3, 2.042e-3, 7.439e-3, 2.200e-2, 3.164e-2, + 3.161e-2, 2.486e-2, 1.664e-2, 7.562e-3, 3.044e-3, 1.608e-3, 3.225e-4, 7.120e-5, 6.290e-6, 1.066e-6))// EF + private val sumexcEeV = doubleArrayOf(12.73, 13.20, 14.77, 15.3, 14.93, 15.4, 13.06) + + private fun _sumexc(K: Double): Double { + var n: Int = 0 + var j: Int + var jmin = 0 + val nmax: Int = 6 + var En: Double + var sum: Double = 0.0 + val f = DoubleArray(7) + val x4 = DoubleArray(4) + val f4 = DoubleArray(4) + + // + while (n <= nmax) { + En = sumexcEeV[n] / 27.21 // En is the excitation energy in Hartree atomic units + when { + K >= 5.0 -> f[n] = 0.0 + K in 3.0..4.0 -> f[n] = sumexcfvec[n][12] + (K - 3.0) * (sumexcfvec[n][13] - sumexcfvec[n][12]) + K in 4.0..5.0 -> f[n] = sumexcfvec[n][13] + (K - 4.0) * (sumexcfvec[n][14] - sumexcfvec[n][13]) + else -> { + j = 0 + while (j < 14) { + if (K >= sumexcKvec[j] && K <= sumexcKvec[j + 1]) { + jmin = j - 1 + } + j++ + } + if (jmin < 0) { + jmin = 0 + } + if (jmin > 11) { + jmin = 11 + } + j = 0 + while (j <= 3) { + x4[j] = sumexcKvec[jmin + j] + f4[j] = sumexcfvec[n][jmin + j] + j++ + } + f[n] = lagrange(4, x4, f4, K) + } + } + sum += f[n] / En + n++ + } + return sum + } + + //Caching function for precision + private val sumexcCache = FunctionCache(0.01, this::_sumexc) + + private fun sumexc(K: Double): Double = sumexcCache(K) + + private fun lagrange(n: Int, xn: DoubleArray, fn: DoubleArray, x: Double): Double { + var i: Int + var j: Int = 0 + var f: Double = 0.0 + var aa: Double + var bb: Double + val a = DoubleArray(100) + val b = DoubleArray(100) + while (j < n) { + i = 0 + while (i < n) { + a[i] = x - xn[i] + b[i] = xn[j] - xn[i] + i++ + } + bb = 1.0 + aa = bb + b[j] = aa + a[j] = b[j] + i = 0 + while (i < n) { + aa *= a[i] + bb *= b[i] + i++ + } + f += fn[j] * aa / bb + j++ + } + return f + } + + // This function computes the total elastic cross section of + // electron scatt. on molecular hydrogen. + // See: Liu, Phys. Rev. A35 (1987) 591, + // Trajmar, Phys Reports 97 (1983) 221. + // E: incident electron energy in eV + // sigmael: cross section in m^2 + private val sigmaelE = doubleArrayOf(0.0, 1.5, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 60.0, 100.0, 150.0, 200.0, 300.0, 400.0) + private val sigmaelS = doubleArrayOf(9.6, 13.0, 15.0, 12.0, 10.0, 7.0, 5.6, 3.3, 1.1, 0.9, 0.5, 0.36, 0.23, 0.15) + + fun sigmael(E: Double): Double { + val gam: Double + var sigma = 0.0 + val T: Double = E / 27.2 + var i: Int + if (E >= 400.0) { + gam = (emass + T) / emass + sigma = gam * gam * Math.PI / (2.0 * T) * (4.2106 - 1.0 / T) * a02 + } else { + i = 0 + while (i <= 12) { + if (E >= sigmaelE[i] && E < sigmaelE[i + 1]) { + sigma = 1e-20 * (sigmaelS[i] + (sigmaelS[i + 1] - sigmaelS[i]) * (E - sigmaelE[i]) / (sigmaelE[i + 1] - sigmaelE[i])) + } + i++ + } + } + return sigma + } + + fun sigmaexc(E: Double): Double { + // This function computes the electronic excitation cross section of + // electron scatt. on molecular hydrogen. + // E: incident electron energy in eV, + // sigmaexc: cross section in m^2 + return when { + E < 9.8 -> 1e-40 + E in 9.8..250.0 -> sigmaBC(E) + sigmadiss10(E) + sigmadiss15(E) + else -> 4.0 * Math.PI * a02 * R / E * (0.80 * log(E / R) + 0.28) + } + // sigma=sigmainel(E)-sigmaion(E); + } + + fun sigmaion(E: Double): Double { + // This function computes the total ionization cross section of + // electron scatt. on molecular hydrogen. + // E: incident electron energy in eV, + // sigmaion: total ionization cross section of + // e+H2 --> e+e+H2^+ or e+e+H^+ +H + // process in m^2. + // + // E<250 eV: Eq. 5 of J. Chem. Phys. 104 (1996) 2956 + // E>250: sigma_i formula on page 107 in + // Phys. Rev. A7 (1973) 103. + // Good agreement with measured results of + // PR A 54 (1996) 2146, and + // Physica 31 (1965) 94. + // + val B = 15.43 + val U = 15.98 + val sigma: Double + val t: Double + val u: Double + val S: Double + val r: Double + val lnt: Double + if (E < 16.0) { + sigma = 1e-40 + } else if (E in 16.0..250.0) { + t = E / B + u = U / B + r = R / B + S = 4.0 * Math.PI * a02 * 2.0 * r * r + lnt = log(t) + sigma = S / (t + u + 1.0) * (lnt / 2.0 * (1.0 - 1.0 / (t * t)) + 1.0 - 1.0 / t - lnt / (t + 1.0)) + } else { + sigma = 4.0 * Math.PI * a02 * R / E * (0.82 * log(E / R) + 1.3) + } + return sigma + } + + // This function computes the sigmaexc electronic excitation + // cross section to the B and C states, with energy loss + // about 12.5 eV. + // E is incident electron energy in eV, + // sigmaexc in m^2 + private val aB = doubleArrayOf(-4.2935194e2, 5.1122109e2, -2.8481279e2, 8.8310338e1, -1.6659591e1, 1.9579609, -1.4012824e-1, 5.5911348e-3, -9.5370103e-5) + private val aC = doubleArrayOf(-8.1942684e2, 9.8705099e2, -5.3095543e2, 1.5917023e2, -2.9121036e1, 3.3321027, -2.3305961e-1, 9.1191781e-3, -1.5298950e-4) + + private fun sigmaBC(E: Double): Double { + var lnsigma: Double = 0.0 + var lnE: Double = log(E) + var lnEn: Double = 1.0 + val sigmaB: Double + var Emin: Double = 12.5 + var sigma: Double = 0.0 + val sigmaC: Double + var n: Int + if (E < Emin) { + sigmaB = 0.0 + } else { + n = 0 + while (n <= 8) { + lnsigma += aB[n] * lnEn + lnEn *= lnE + n++ + } + sigmaB = exp(lnsigma) + } + sigma += sigmaB + // sigma=0.; + // C state: + Emin = 15.8 + lnE = log(E) + lnEn = 1.0 + lnsigma = 0.0 + if (E < Emin) { + sigmaC = 0.0 + } else { + n = 0 + while (n <= 8) { + lnsigma += aC[n] * lnEn + lnEn *= lnE + n++ + } + sigmaC = exp(lnsigma) + } + sigma += sigmaC + return sigma * 1e-4 + } + + ////////////////////////////////////////////////////////////////// + + // This function computes the sigmadiss10 electronic + // dissociative excitation + // cross section, with energy loss + // about 10 eV. + // E is incident electron energy in eV, + // sigmadiss10 in m^2 + private val sigmadiss10a = doubleArrayOf(-2.297914361e5, 5.303988579e5, -5.316636672e5, 3.022690779e5, -1.066224144e5, 2.389841369e4, -3.324526406e3, 2.624761592e2, -9.006246604) + + private fun sigmadiss10(E: Double): Double { + var lnsigma: Double = 0.0 + val lnE: Double = log(E) + var lnEn: Double = 1.0 + val Emin = 9.8 + var n: Int + // E is in eV + val sigma = if (E < Emin) { + 0.0 + } else { + n = 0 + while (n <= 8) { + lnsigma += sigmadiss10a[n] * lnEn + lnEn *= lnE + n++ + } + exp(lnsigma) + } + return sigma * 1e-4 + } + + ////////////////////////////////////////////////////////////////// + // This function computes the sigmadiss15 electronic + // dissociative excitation + // cross section, with energy loss + // about 15 eV. + // E is incident electron energy in eV, + // sigmadiss15 in m^2 + private val sigmadiss15a = doubleArrayOf(-1.157041752e3, 1.501936271e3, -8.6119387e2, 2.754926257e2, -5.380465012e1, 6.573972423, -4.912318139e-1, 2.054926773e-2, -3.689035889e-4) + + private fun sigmadiss15(E: Double): Double { + var lnsigma: Double = 0.0 + val lnE: Double = log(E) + val Emin: Double = 16.5 + var n: Int + // E is in eV + var lnEn: Double = 1.0 + val sigma = if (E < Emin) { + 0.0 + } else { + n = 0 + while (n <= 8) { + lnsigma += sigmadiss15a[n] * lnEn + lnEn *= lnE + n++ + } + exp(lnsigma) + } + return sigma * 1e-4 + } + + /** + * Полное сечение с учетом квазиупругих столкновений + * + * @param E + * @return + */ + fun sigmaTotal(E: Double): Double { + return sigmael(E) + sigmaexc(E) + sigmaion(E) + + } +} diff --git a/src/main/kotlin/inr/numass/trapping/SimulationManager.kt b/src/main/kotlin/ru/inr/mass/trapping/SimulationManager.kt similarity index 96% rename from src/main/kotlin/inr/numass/trapping/SimulationManager.kt rename to src/main/kotlin/ru/inr/mass/trapping/SimulationManager.kt index 8a62bf1..395e53c 100644 --- a/src/main/kotlin/inr/numass/trapping/SimulationManager.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/SimulationManager.kt @@ -1,197 +1,197 @@ -package inr.numass.trapping - -import org.apache.commons.math3.analysis.interpolation.LinearInterpolator -import org.apache.commons.math3.random.JDKRandomGenerator -import org.apache.commons.rng.UniformRandomProvider -import org.apache.commons.rng.simple.RandomSource -import java.io.File -import java.io.PrintStream -import java.nio.file.Files -import java.nio.file.StandardOpenOption -import java.util.stream.LongStream - -private val seedGenerator = JDKRandomGenerator() - - -/** - * Created by darksnake on 04-Jun-16. - */ -class SimulationManager() { - - var outputDirectory: File = File("./output") - var fileName = "trap[test]" - - var comment = "" - - /** - * A supplier for random generator. Each track has its own generator - */ - var generatorFactory: (Long) -> UniformRandomProvider = { RandomSource.create(RandomSource.MT_64, seedGenerator.nextInt()) } - var reportFilter: (Simulator.SimulationResult) -> Boolean = { it.state == Simulator.EndState.ACCEPTED } - - var initialE = 18000.0 - var eLow: Double = 14000.0 - var thetaTransport: Double = 24.107064 / 180 * Math.PI - var thetaPinch: Double = 19.481097 / 180 * Math.PI - var gasDensity: Double = 5e20// m^-3 - var bSource: Double = 0.6 - var magneticField: ((Double) -> Double)? = null - - /** - * A syntentic property which allows to set lower energy by specifying range instead of energy itself - */ - var range: Double - get() = initialE - eLow - set(value) { - eLow = initialE - value - } - - -// fun setOutputFile(fileName: String) { -// val outputFile = File(fileName) -// if (!outputFile.exists()) { -// outputFile.parentFile.mkdirs() -// outputFile.createNewFile() -// } -// this.output = PrintStream(FileOutputStream(outputFile)) -// } - - - fun withReportFilter(filter: (Simulator.SimulationResult) -> Boolean): SimulationManager { - this.reportFilter = filter - return this - } - - fun setFields(Bsource: Double, Btransport: Double, Bpinch: Double) { - this.bSource = Bsource - this.thetaTransport = Math.asin(Math.sqrt(Bsource / Btransport)) - this.thetaPinch = Math.asin(Math.sqrt(Bsource / Bpinch)) - } - - /** - * Set field map from values - * - * @param z - * @param b - * @return - */ - fun setFieldMap(z: DoubleArray, b: DoubleArray) { - this.magneticField = { LinearInterpolator().interpolate(z, b).value(it) } - } - - /** - * Симулируем пролет num электронов. - * - * @param num - * @return - */ - @Synchronized - fun simulateAll(num: Number): Counter { - if (!outputDirectory.exists()) { - outputDirectory.mkdirs() - } - - - val simulator = Simulator(eLow, thetaTransport, thetaPinch, gasDensity, bSource, magneticField) - - val counter = Counter() - - val header = """ - E_init = $initialE; - E_low = $eLow; - theta_pinch = $thetaPinch; - theta_transport = $thetaTransport; - density = $gasDensity; - """.trimIndent() + "\n\n" + comment - - - val outputPath = outputDirectory.toPath().resolve("$fileName.out") - - PrintStream(Files.newOutputStream(outputPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)).use { output -> - output.println("# " + header.replace("\n", "\n# "))//adding comment symbols - - System.out.printf("%nStarting simulation with initial energy %g and %d electrons.%n%n", initialE, num.toLong()) - output.printf("%s\t%s\t%s\t%s\t%s\t%s\t%s%n", "id", "E", "theta", "theta_start", "colNum", "L", "state") - LongStream.rangeClosed(1, num.toLong()).parallel() - .mapToObj { id -> - val generator = RandomGeneratorBridge(generatorFactory(id)) - val theta = Math.acos(1 - 2 * generator.nextDouble())// from 0 to Pi - val z = (generator.nextDouble() - 0.5) * Simulator.SOURCE_LENGTH - simulator.simulate(id, generator, initialE, theta, z).also { counter.count(it) } - } - .filter(reportFilter) - .forEach { res -> - printOne(output, res) - } - } - - val statisticsPath = outputDirectory.toPath().resolve("$fileName.stat") - PrintStream(Files.newOutputStream(statisticsPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)).use { - it.println(header + "\n") - printStatistics(it, simulator, counter) - - } - return counter - } - - private fun printStatistics(output: PrintStream, simulator: Simulator, counter: Counter) { - output.apply { - println() - println("***RESULT***") - printf("The total number of events is %d.%n%n", counter.count) - printf("The spectrometer acceptance angle is %g.%n", simulator.thetaPinch * 180 / Math.PI) - printf("The transport reflection angle is %g.%n", simulator.thetaTransport * 180 / Math.PI) - printf("The starting energy is %g.%n", initialE) - printf("The lower energy boundary is %g.%n", simulator.eLow) - printf("The source density is %g.%n", simulator.gasDensity) - - println() - printf("The total number of ACCEPTED events is %d.%n", counter.accepted) - printf("The total number of PASS events is %d.%n", counter.pass) - printf("The total number of REJECTED events is %d.%n", counter.rejected) - printf("The total number of LOWENERGY events is %d.%n%n", counter.lowE) - } - - } - - private fun printOne(out: PrintStream, res: Simulator.SimulationResult) { - out.printf("%d\t%g\t%g\t%g\t%d\t%g\t%s%n", res.id, res.E, res.theta * 180 / Math.PI, res.initTheta * 180 / Math.PI, res.collisionNumber, res.l, res.state.toString()) - out.flush() - } - - - /** - * Statistic counter - */ - class Counter { - internal var accepted = 0 - internal var pass = 0 - internal var rejected = 0 - internal var lowE = 0 - internal var count = 0 - - fun count(res: Simulator.SimulationResult): Simulator.SimulationResult { - synchronized(this) { - count++ - when (res.state) { - Simulator.EndState.ACCEPTED -> accepted++ - Simulator.EndState.LOWENERGY -> lowE++ - Simulator.EndState.PASS -> pass++ - Simulator.EndState.REJECTED -> rejected++ - Simulator.EndState.NONE -> throw IllegalStateException() - } - } - return res - } - - @Synchronized - fun reset() { - count = 0 - accepted = 0 - pass = 0 - rejected = 0 - lowE = 0 - } - - } -} +package ru.inr.mass.trapping + +import org.apache.commons.math3.analysis.interpolation.LinearInterpolator +import org.apache.commons.math3.random.JDKRandomGenerator +import org.apache.commons.rng.UniformRandomProvider +import org.apache.commons.rng.simple.RandomSource +import java.io.File +import java.io.PrintStream +import java.nio.file.Files +import java.nio.file.StandardOpenOption +import java.util.stream.LongStream + +private val seedGenerator = JDKRandomGenerator() + + +/** + * Created by darksnake on 04-Jun-16. + */ +class SimulationManager() { + + var outputDirectory: File = File("./output") + var fileName = "trap[test]" + + var comment = "" + + /** + * A supplier for random generator. Each track has its own generator + */ + var generatorFactory: (Long) -> UniformRandomProvider = { RandomSource.create(RandomSource.MT_64, seedGenerator.nextInt()) } + var reportFilter: (Simulator.SimulationResult) -> Boolean = { it.state == Simulator.EndState.ACCEPTED } + + var initialE = 18000.0 + var eLow: Double = 14000.0 + var thetaTransport: Double = 24.107064 / 180 * Math.PI + var thetaPinch: Double = 19.481097 / 180 * Math.PI + var gasDensity: Double = 5e20// m^-3 + var bSource: Double = 0.6 + var magneticField: ((Double) -> Double)? = null + + /** + * A syntentic property which allows to set lower energy by specifying range instead of energy itself + */ + var range: Double + get() = initialE - eLow + set(value) { + eLow = initialE - value + } + + +// fun setOutputFile(fileName: String) { +// val outputFile = File(fileName) +// if (!outputFile.exists()) { +// outputFile.parentFile.mkdirs() +// outputFile.createNewFile() +// } +// this.output = PrintStream(FileOutputStream(outputFile)) +// } + + + fun withReportFilter(filter: (Simulator.SimulationResult) -> Boolean): SimulationManager { + this.reportFilter = filter + return this + } + + fun setFields(Bsource: Double, Btransport: Double, Bpinch: Double) { + this.bSource = Bsource + this.thetaTransport = Math.asin(Math.sqrt(Bsource / Btransport)) + this.thetaPinch = Math.asin(Math.sqrt(Bsource / Bpinch)) + } + + /** + * Set field map from values + * + * @param z + * @param b + * @return + */ + fun setFieldMap(z: DoubleArray, b: DoubleArray) { + this.magneticField = { LinearInterpolator().interpolate(z, b).value(it) } + } + + /** + * Симулируем пролет num электронов. + * + * @param num + * @return + */ + @Synchronized + fun simulateAll(num: Number): Counter { + if (!outputDirectory.exists()) { + outputDirectory.mkdirs() + } + + + val simulator = Simulator(eLow, thetaTransport, thetaPinch, gasDensity, bSource, magneticField) + + val counter = Counter() + + val header = """ + E_init = $initialE; + E_low = $eLow; + theta_pinch = $thetaPinch; + theta_transport = $thetaTransport; + density = $gasDensity; + """.trimIndent() + "\n\n" + comment + + + val outputPath = outputDirectory.toPath().resolve("$fileName.out") + + PrintStream(Files.newOutputStream(outputPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)).use { output -> + output.println("# " + header.replace("\n", "\n# "))//adding comment symbols + + System.out.printf("%nStarting simulation with initial energy %g and %d electrons.%n%n", initialE, num.toLong()) + output.printf("%s\t%s\t%s\t%s\t%s\t%s\t%s%n", "id", "E", "theta", "theta_start", "colNum", "L", "state") + LongStream.rangeClosed(1, num.toLong()).parallel() + .mapToObj { id -> + val generator = RandomGeneratorBridge(generatorFactory(id)) + val theta = Math.acos(1 - 2 * generator.nextDouble())// from 0 to Pi + val z = (generator.nextDouble() - 0.5) * Simulator.SOURCE_LENGTH + simulator.simulate(id, generator, initialE, theta, z).also { counter.count(it) } + } + .filter(reportFilter) + .forEach { res -> + printOne(output, res) + } + } + + val statisticsPath = outputDirectory.toPath().resolve("$fileName.stat") + PrintStream(Files.newOutputStream(statisticsPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)).use { + it.println(header + "\n") + printStatistics(it, simulator, counter) + + } + return counter + } + + private fun printStatistics(output: PrintStream, simulator: Simulator, counter: Counter) { + output.apply { + println() + println("***RESULT***") + printf("The total number of events is %d.%n%n", counter.count) + printf("The spectrometer acceptance angle is %g.%n", simulator.thetaPinch * 180 / Math.PI) + printf("The transport reflection angle is %g.%n", simulator.thetaTransport * 180 / Math.PI) + printf("The starting energy is %g.%n", initialE) + printf("The lower energy boundary is %g.%n", simulator.eLow) + printf("The source density is %g.%n", simulator.gasDensity) + + println() + printf("The total number of ACCEPTED events is %d.%n", counter.accepted) + printf("The total number of PASS events is %d.%n", counter.pass) + printf("The total number of REJECTED events is %d.%n", counter.rejected) + printf("The total number of LOWENERGY events is %d.%n%n", counter.lowE) + } + + } + + private fun printOne(out: PrintStream, res: Simulator.SimulationResult) { + out.printf("%d\t%g\t%g\t%g\t%d\t%g\t%s%n", res.id, res.E, res.theta * 180 / Math.PI, res.initTheta * 180 / Math.PI, res.collisionNumber, res.l, res.state.toString()) + out.flush() + } + + + /** + * Statistic counter + */ + class Counter { + internal var accepted = 0 + internal var pass = 0 + internal var rejected = 0 + internal var lowE = 0 + internal var count = 0 + + fun count(res: Simulator.SimulationResult): Simulator.SimulationResult { + synchronized(this) { + count++ + when (res.state) { + Simulator.EndState.ACCEPTED -> accepted++ + Simulator.EndState.LOWENERGY -> lowE++ + Simulator.EndState.PASS -> pass++ + Simulator.EndState.REJECTED -> rejected++ + Simulator.EndState.NONE -> throw IllegalStateException() + } + } + return res + } + + @Synchronized + fun reset() { + count = 0 + accepted = 0 + pass = 0 + rejected = 0 + lowE = 0 + } + + } +} diff --git a/src/main/kotlin/inr/numass/trapping/Simulator.kt b/src/main/kotlin/ru/inr/mass/trapping/Simulator.kt similarity index 97% rename from src/main/kotlin/inr/numass/trapping/Simulator.kt rename to src/main/kotlin/ru/inr/mass/trapping/Simulator.kt index 6ce096b..f248255 100644 --- a/src/main/kotlin/inr/numass/trapping/Simulator.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/Simulator.kt @@ -1,435 +1,437 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package inr.numass.trapping - -import org.apache.commons.math3.distribution.ExponentialDistribution -import org.apache.commons.math3.geometry.euclidean.threed.Rotation -import org.apache.commons.math3.geometry.euclidean.threed.SphericalCoordinates -import org.apache.commons.math3.random.RandomGenerator -import org.apache.commons.math3.util.FastMath.* -import org.apache.commons.math3.util.Pair -import org.apache.commons.math3.util.Precision - -/** - * @author Darksnake - * @property magneticField Longitudal magnetic field distribution - * @property gasDensity gas density in 1/m^3 - */ -class Simulator( - val eLow: Double, - val thetaTransport: Double, - val thetaPinch: Double, - val gasDensity: Double,// m^-3 - val bSource: Double, - val magneticField: ((Double) -> Double)? -) { - - enum class EndState { - - ACCEPTED, //трэппинговый электрон попал в аксептанс - REJECTED, //трэппинговый электрон вылетел через заднюю пробку - LOWENERGY, //потерял слишком много энергии - PASS, //электрон никогда не запирался и прошел напрямую, нужно для нормировки - NONE - } - - - /** - * Perform scattering in the given position - * - * @param pos - * @return - */ - private fun scatter(pos: State): State { - //Вычисляем сечения и нормируем их на полное сечение - var sigmaIon = Scatter.sigmaion(pos.e) - var sigmaEl = Scatter.sigmael(pos.e) - var sigmaExc = Scatter.sigmaexc(pos.e) - val sigmaTotal = sigmaEl + sigmaIon + sigmaExc - sigmaIon /= sigmaTotal - sigmaEl /= sigmaTotal - sigmaExc /= sigmaTotal - - //проверяем нормировку - assert(Precision.equals(sigmaEl + sigmaExc + sigmaIon, 1.0, 1e-2)) - - val alpha = pos.generator.nextDouble() - - val delta: Pair = when { - alpha < sigmaEl -> Scatter.randomel(pos.e, pos.generator)// elastic - alpha > sigmaEl + sigmaExc -> Scatter.randomion(pos.e, pos.generator)//ionization case - else -> Scatter.randomexc(pos.e, pos.generator)//excitation case - } - - //Обновляем значени угла и энергии независимо ни от чего - pos.substractE(delta.first) - //Изменение угла - pos.addTheta(delta.second / 180 * Math.PI) - - return pos - } - - /** - * Calculate distance to the next scattering - * - * @param e - * @return - */ - private fun freePath(generator: RandomGenerator, e: Double): Double { - //FIXME redundant cross-section calculation - //All cross-sections are in m^2 - return ExponentialDistribution(generator, 1.0 / Scatter.sigmaTotal(e) / gasDensity).sample() - } - - /** - * Calculate propagated position before scattering - * - * @param deltaL - * @return z shift and reflection counter - */ - private fun propagate(pos: State, deltaL: Double): State { - // if magnetic field not defined, consider it to be uniform and equal bSource - if (magneticField == null) { - val deltaZ = deltaL * cos(pos.theta) // direction already included in cos(theta) - // double z0 = pos.z; - pos.addZ(deltaZ) - pos.l += deltaL - - // //if we are crossing source boundary, check for end condition - // while (abs(deltaZ + pos.z) > SOURCE_LENGTH / 2d && !pos.isFinished()) { - // - // pos.checkEndState(); - // } - // - // // if track is finished apply boundary position - // if (pos.isFinished()) { - // // remembering old z to correctly calculate total l - // double oldz = pos.z; - // pos.z = pos.direction() * SOURCE_LENGTH / 2d; - // pos.l += (pos.z - oldz) / cos(pos.theta); - // } else { - // //else just add z - // pos.l += deltaL; - // pos.addZ(deltaZ); - // } - - return pos - } else { - var curL = 0.0 - val sin2 = sin(pos.theta) * sin(pos.theta) - - while (curL <= deltaL - 0.01 && !pos.isFinished) { - //an l step - val delta = min(deltaL - curL, DELTA_L) - - val b = field(pos.z) - - val root = 1 - sin2 * b / bSource - //preliminary reflection - if (root < 0) { - pos.flip() - } - pos.addZ(pos.direction() * delta * sqrt(abs(root))) - // // change direction in case of reflection. Loss of precision here? - // if (root < 0) { - // // check if end state occurred. seem to never happen since it is reflection case - // pos.checkEndState(); - // // finish if it does - // if (pos.isFinished()) { - // //TODO check if it happens - // return pos; - // } else { - // //flip direction - // pos.flip(); - // // move in reversed direction - // pos.z += pos.direction() * delta * sqrt(-root); - // } - // - // } else { - // // move forward - // pos.z += pos.direction() * delta * sqrt(root); - // //check if it is exit case - // if (abs(pos.z) > SOURCE_LENGTH / 2d) { - // // check if electron is out - // pos.checkEndState(); - // // finish if it is - // if (pos.isFinished()) { - // return pos; - // } - // // PENDING no need to apply reflection, it is applied automatically when root < 0 - // pos.z = signum(pos.z) * SOURCE_LENGTH / 2d; - // if (signum(pos.z) == pos.direction()) { - // pos.flip(); - // } - // } - // } - - - curL += delta - pos.l += delta - } - return pos - } - } - - /** - * Magnetic field in the z point - * - * @param z - * @return - */ - private fun field(z: Double): Double { - return magneticField?.invoke(z) ?: bSource - } - - /** - * Симулируем один пробег электрона от начального значения и до вылетания из - * иточника или до того момента, как энергия становится меньше eLow. - */ - fun simulate(id: Long, generator: RandomGenerator, initEnergy: Double, initTheta: Double, initZ: Double): SimulationResult { - assert(initEnergy > 0) - assert(initTheta > 0 && initTheta < Math.PI) - assert(abs(initZ) <= SOURCE_LENGTH / 2.0) - - val pos = State(generator, initEnergy, initTheta, initZ) - - while (!pos.isFinished) { - val dl = freePath(generator, pos.e) // path to next scattering - // propagate to next scattering position - propagate(pos, dl) - - if (!pos.isFinished) { - // perform scatter - scatter(pos) - // increase collision number - pos.colNum++ - if (pos.e < eLow) { - //Если энергия стала слишком маленькой - pos.setEndState(EndState.LOWENERGY) - } - } - } - - return SimulationResult(id, pos.endState, pos.e, pos.theta, initTheta, pos.colNum, pos.l) - } - - fun resetDebugCounters() { - debug = true - counter.resetAll() - } - - fun printDebugCounters() { - if (debug) { - counter.print(System.out) - } else { - throw RuntimeException("Debug not initiated") - } - } - - data class SimulationResult(val id: Long, val state: EndState, val E: Double, val theta: Double, val initTheta: Double, val collisionNumber: Int, val l: Double) - - /** - * Current electron position in simulation. Not thread safe! - * - * @property e Current energy - * @property theta Current theta recalculated to the field in the center of the source - * @property z current z. Zero is the center of the source - */ - private inner class State(val generator: RandomGenerator, internal var e: Double, internal var theta: Double, internal var z: Double) { - /** - * Current total path - */ - var l = 0.0 - - /** - * Number of scatterings - */ - var colNum = 0 - - var endState = EndState.NONE - - internal val isForward: Boolean - get() = theta <= Math.PI / 2 - - internal val isFinished: Boolean - get() = this.endState != EndState.NONE - - /** - * @param dE - * @return resulting E - */ - internal fun substractE(dE: Double): Double { - this.e -= dE - return e - } - - internal fun direction(): Double { - return (if (isForward) 1 else -1).toDouble() - } - - internal fun setEndState(state: EndState) { - this.endState = state - } - - /** - * add Z and calculate direction change - * - * @param dZ - * @return - */ - internal fun addZ(dZ: Double): Double { - this.z += dZ - while (abs(this.z) > SOURCE_LENGTH / 2.0 && !isFinished) { - // reflecting from back wall - if (z < 0) { - if (theta >= PI - thetaTransport) { - setEndState(EndState.REJECTED) - } - z = if (isFinished) { - -SOURCE_LENGTH / 2.0 - } else { - // reflecting from rear pinch - -SOURCE_LENGTH - z - } - } else { - if (theta < thetaPinch) { - if (colNum == 0) { - //counting pass electrons - setEndState(EndState.PASS) - } else { - setEndState(EndState.ACCEPTED) - } - } - z = if (isFinished) { - SOURCE_LENGTH / 2.0 - } else { - // reflecting from forward transport magnet - SOURCE_LENGTH - z - } - } - if (!isFinished) { - flip() - } - } - return z - } - - // /** - // * Check if this position is an end state and apply it if necessary. Does not check z position. - // * - // * @return - // */ - // private void checkEndState() { - // //accepted by spectrometer - // if (theta < thetaPinch) { - // if (colNum == 0) { - // //counting pass electrons - // setEndState(EndState.PASS); - // } else { - // setEndState(EndState.ACCEPTED); - // } - // } - // - // //through the rear magnetic pinch - // if (theta >= PI - thetaTransport) { - // setEndState(EndState.REJECTED); - // } - // } - - /** - * Reverse electron direction - */ - fun flip() { - if (theta < 0 || theta > PI) { - throw Error() - } - theta = PI - theta - } - - /** - * Magnetic field in the current point - * - * @return - */ - fun field(): Double { - return this@Simulator.field(z) - } - - /** - * Real theta angle in current point - * - * @return - */ - fun realTheta(): Double { - if (magneticField == null) { - return theta - } else { - var newTheta = asin(min(abs(sin(theta)) * sqrt(field() / bSource), 1.0)) - if (theta > PI / 2) { - newTheta = PI - newTheta - } - - assert(!java.lang.Double.isNaN(newTheta)) - return newTheta - } - } - - - /** - * Сложение вектора с учетом случайно распределения по фи - * - * @param dTheta - * @return resulting angle - */ - fun addTheta(dTheta: Double): Double { - //Генерируем случайный фи - val phi = generator.nextDouble() * 2.0 * Math.PI - - //change to real angles - val realTheta = realTheta() - //Создаем начальный вектор в сферических координатах - val init = SphericalCoordinates(1.0, 0.0, realTheta + dTheta) - // Задаем вращение относительно оси, перпендикулярной исходному вектору - val rotate = SphericalCoordinates(1.0, 0.0, realTheta) - // поворачиваем исходный вектор на dTheta - val rot = Rotation(rotate.cartesian, phi, null) - - val result = rot.applyTo(init.cartesian) - - val newTheta = acos(result.z) - - // //следим чтобы угол был от 0 до Pi - // if (newtheta < 0) { - // newtheta = -newtheta; - // } - // if (newtheta > Math.PI) { - // newtheta = 2 * Math.PI - newtheta; - // } - - //change back to virtual angles - if (magneticField == null) { - theta = newTheta - } else { - theta = asin(sin(newTheta) * sqrt(bSource / field())) - if (newTheta > PI / 2) { - theta = PI - theta - } - } - - assert(!java.lang.Double.isNaN(theta)) - - return theta - } - - } - - companion object { - - const val SOURCE_LENGTH = 3.0 - private const val DELTA_L = 0.1 //step for propagate calculation - } - - -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package ru.inr.mass.trapping + +import org.apache.commons.math3.distribution.ExponentialDistribution +import org.apache.commons.math3.geometry.euclidean.threed.Rotation +import org.apache.commons.math3.geometry.euclidean.threed.SphericalCoordinates +import org.apache.commons.math3.random.RandomGenerator +import org.apache.commons.math3.util.FastMath.* +import org.apache.commons.math3.util.Pair +import org.apache.commons.math3.util.Precision +import ru.inr.mass.trapping.Scatter.counter +import ru.inr.mass.trapping.Scatter.debug + +/** + * @author Darksnake + * @property magneticField Longitudal magnetic field distribution + * @property gasDensity gas density in 1/m^3 + */ +class Simulator( + val eLow: Double, + val thetaTransport: Double, + val thetaPinch: Double, + val gasDensity: Double,// m^-3 + val bSource: Double, + val magneticField: ((Double) -> Double)? +) { + + enum class EndState { + + ACCEPTED, //трэппинговый электрон попал в аксептанс + REJECTED, //трэппинговый электрон вылетел через заднюю пробку + LOWENERGY, //потерял слишком много энергии + PASS, //электрон никогда не запирался и прошел напрямую, нужно для нормировки + NONE + } + + + /** + * Perform scattering in the given position + * + * @param pos + * @return + */ + private fun scatter(pos: State): State { + //Вычисляем сечения и нормируем их на полное сечение + var sigmaIon = Scatter.sigmaion(pos.e) + var sigmaEl = Scatter.sigmael(pos.e) + var sigmaExc = Scatter.sigmaexc(pos.e) + val sigmaTotal = sigmaEl + sigmaIon + sigmaExc + sigmaIon /= sigmaTotal + sigmaEl /= sigmaTotal + sigmaExc /= sigmaTotal + + //проверяем нормировку + assert(Precision.equals(sigmaEl + sigmaExc + sigmaIon, 1.0, 1e-2)) + + val alpha = pos.generator.nextDouble() + + val delta: Pair = when { + alpha < sigmaEl -> Scatter.randomel(pos.e, pos.generator)// elastic + alpha > sigmaEl + sigmaExc -> Scatter.randomion(pos.e, pos.generator)//ionization case + else -> Scatter.randomexc(pos.e, pos.generator)//excitation case + } + + //Обновляем значени угла и энергии независимо ни от чего + pos.substractE(delta.first) + //Изменение угла + pos.addTheta(delta.second / 180 * Math.PI) + + return pos + } + + /** + * Calculate distance to the next scattering + * + * @param e + * @return + */ + private fun freePath(generator: RandomGenerator, e: Double): Double { + //FIXME redundant cross-section calculation + //All cross-sections are in m^2 + return ExponentialDistribution(generator, 1.0 / Scatter.sigmaTotal(e) / gasDensity).sample() + } + + /** + * Calculate propagated position before scattering + * + * @param deltaL + * @return z shift and reflection counter + */ + private fun propagate(pos: State, deltaL: Double): State { + // if magnetic field not defined, consider it to be uniform and equal bSource + if (magneticField == null) { + val deltaZ = deltaL * cos(pos.theta) // direction already included in cos(theta) + // double z0 = pos.z; + pos.addZ(deltaZ) + pos.l += deltaL + + // //if we are crossing source boundary, check for end condition + // while (abs(deltaZ + pos.z) > SOURCE_LENGTH / 2d && !pos.isFinished()) { + // + // pos.checkEndState(); + // } + // + // // if track is finished apply boundary position + // if (pos.isFinished()) { + // // remembering old z to correctly calculate total l + // double oldz = pos.z; + // pos.z = pos.direction() * SOURCE_LENGTH / 2d; + // pos.l += (pos.z - oldz) / cos(pos.theta); + // } else { + // //else just add z + // pos.l += deltaL; + // pos.addZ(deltaZ); + // } + + return pos + } else { + var curL = 0.0 + val sin2 = sin(pos.theta) * sin(pos.theta) + + while (curL <= deltaL - 0.01 && !pos.isFinished) { + //an l step + val delta = min(deltaL - curL, DELTA_L) + + val b = field(pos.z) + + val root = 1 - sin2 * b / bSource + //preliminary reflection + if (root < 0) { + pos.flip() + } + pos.addZ(pos.direction() * delta * sqrt(abs(root))) + // // change direction in case of reflection. Loss of precision here? + // if (root < 0) { + // // check if end state occurred. seem to never happen since it is reflection case + // pos.checkEndState(); + // // finish if it does + // if (pos.isFinished()) { + // //TODO check if it happens + // return pos; + // } else { + // //flip direction + // pos.flip(); + // // move in reversed direction + // pos.z += pos.direction() * delta * sqrt(-root); + // } + // + // } else { + // // move forward + // pos.z += pos.direction() * delta * sqrt(root); + // //check if it is exit case + // if (abs(pos.z) > SOURCE_LENGTH / 2d) { + // // check if electron is out + // pos.checkEndState(); + // // finish if it is + // if (pos.isFinished()) { + // return pos; + // } + // // PENDING no need to apply reflection, it is applied automatically when root < 0 + // pos.z = signum(pos.z) * SOURCE_LENGTH / 2d; + // if (signum(pos.z) == pos.direction()) { + // pos.flip(); + // } + // } + // } + + + curL += delta + pos.l += delta + } + return pos + } + } + + /** + * Magnetic field in the z point + * + * @param z + * @return + */ + private fun field(z: Double): Double { + return magneticField?.invoke(z) ?: bSource + } + + /** + * Симулируем один пробег электрона от начального значения и до вылетания из + * иточника или до того момента, как энергия становится меньше eLow. + */ + fun simulate(id: Long, generator: RandomGenerator, initEnergy: Double, initTheta: Double, initZ: Double): SimulationResult { + assert(initEnergy > 0) + assert(initTheta > 0 && initTheta < Math.PI) + assert(abs(initZ) <= SOURCE_LENGTH / 2.0) + + val pos = State(generator, initEnergy, initTheta, initZ) + + while (!pos.isFinished) { + val dl = freePath(generator, pos.e) // path to next scattering + // propagate to next scattering position + propagate(pos, dl) + + if (!pos.isFinished) { + // perform scatter + scatter(pos) + // increase collision number + pos.colNum++ + if (pos.e < eLow) { + //Если энергия стала слишком маленькой + pos.setEndState(EndState.LOWENERGY) + } + } + } + + return SimulationResult(id, pos.endState, pos.e, pos.theta, initTheta, pos.colNum, pos.l) + } + + fun resetDebugCounters() { + debug = true + counter.resetAll() + } + + fun printDebugCounters() { + if (debug) { + counter.print(System.out) + } else { + throw RuntimeException("Debug not initiated") + } + } + + data class SimulationResult(val id: Long, val state: EndState, val E: Double, val theta: Double, val initTheta: Double, val collisionNumber: Int, val l: Double) + + /** + * Current electron position in simulation. Not thread safe! + * + * @property e Current energy + * @property theta Current theta recalculated to the field in the center of the source + * @property z current z. Zero is the center of the source + */ + private inner class State(val generator: RandomGenerator, internal var e: Double, internal var theta: Double, internal var z: Double) { + /** + * Current total path + */ + var l = 0.0 + + /** + * Number of scatterings + */ + var colNum = 0 + + var endState = EndState.NONE + + internal val isForward: Boolean + get() = theta <= Math.PI / 2 + + internal val isFinished: Boolean + get() = this.endState != EndState.NONE + + /** + * @param dE + * @return resulting E + */ + internal fun substractE(dE: Double): Double { + this.e -= dE + return e + } + + internal fun direction(): Double { + return (if (isForward) 1 else -1).toDouble() + } + + internal fun setEndState(state: EndState) { + this.endState = state + } + + /** + * add Z and calculate direction change + * + * @param dZ + * @return + */ + internal fun addZ(dZ: Double): Double { + this.z += dZ + while (abs(this.z) > SOURCE_LENGTH / 2.0 && !isFinished) { + // reflecting from back wall + if (z < 0) { + if (theta >= PI - thetaTransport) { + setEndState(EndState.REJECTED) + } + z = if (isFinished) { + -SOURCE_LENGTH / 2.0 + } else { + // reflecting from rear pinch + -SOURCE_LENGTH - z + } + } else { + if (theta < thetaPinch) { + if (colNum == 0) { + //counting pass electrons + setEndState(EndState.PASS) + } else { + setEndState(EndState.ACCEPTED) + } + } + z = if (isFinished) { + SOURCE_LENGTH / 2.0 + } else { + // reflecting from forward transport magnet + SOURCE_LENGTH - z + } + } + if (!isFinished) { + flip() + } + } + return z + } + + // /** + // * Check if this position is an end state and apply it if necessary. Does not check z position. + // * + // * @return + // */ + // private void checkEndState() { + // //accepted by spectrometer + // if (theta < thetaPinch) { + // if (colNum == 0) { + // //counting pass electrons + // setEndState(EndState.PASS); + // } else { + // setEndState(EndState.ACCEPTED); + // } + // } + // + // //through the rear magnetic pinch + // if (theta >= PI - thetaTransport) { + // setEndState(EndState.REJECTED); + // } + // } + + /** + * Reverse electron direction + */ + fun flip() { + if (theta < 0 || theta > PI) { + throw Error() + } + theta = PI - theta + } + + /** + * Magnetic field in the current point + * + * @return + */ + fun field(): Double { + return this@Simulator.field(z) + } + + /** + * Real theta angle in current point + * + * @return + */ + fun realTheta(): Double { + if (magneticField == null) { + return theta + } else { + var newTheta = asin(min(abs(sin(theta)) * sqrt(field() / bSource), 1.0)) + if (theta > PI / 2) { + newTheta = PI - newTheta + } + + assert(!java.lang.Double.isNaN(newTheta)) + return newTheta + } + } + + + /** + * Сложение вектора с учетом случайно распределения по фи + * + * @param dTheta + * @return resulting angle + */ + fun addTheta(dTheta: Double): Double { + //Генерируем случайный фи + val phi = generator.nextDouble() * 2.0 * Math.PI + + //change to real angles + val realTheta = realTheta() + //Создаем начальный вектор в сферических координатах + val init = SphericalCoordinates(1.0, 0.0, realTheta + dTheta) + // Задаем вращение относительно оси, перпендикулярной исходному вектору + val rotate = SphericalCoordinates(1.0, 0.0, realTheta) + // поворачиваем исходный вектор на dTheta + val rot = Rotation(rotate.cartesian, phi, null) + + val result = rot.applyTo(init.cartesian) + + val newTheta = acos(result.z) + + // //следим чтобы угол был от 0 до Pi + // if (newtheta < 0) { + // newtheta = -newtheta; + // } + // if (newtheta > Math.PI) { + // newtheta = 2 * Math.PI - newtheta; + // } + + //change back to virtual angles + if (magneticField == null) { + theta = newTheta + } else { + theta = asin(sin(newTheta) * sqrt(bSource / field())) + if (newTheta > PI / 2) { + theta = PI - theta + } + } + + assert(!java.lang.Double.isNaN(theta)) + + return theta + } + + } + + companion object { + + const val SOURCE_LENGTH = 3.0 + private const val DELTA_L = 0.1 //step for propagate calculation + } + + +} diff --git a/src/main/kotlin/inr/numass/trapping/Trapping.kt b/src/main/kotlin/ru/inr/mass/trapping/Trapping.kt similarity index 91% rename from src/main/kotlin/inr/numass/trapping/Trapping.kt rename to src/main/kotlin/ru/inr/mass/trapping/Trapping.kt index 9ed354d..327617a 100644 --- a/src/main/kotlin/inr/numass/trapping/Trapping.kt +++ b/src/main/kotlin/ru/inr/mass/trapping/Trapping.kt @@ -1,33 +1,33 @@ -package inr.numass.trapping - -import java.time.Duration -import java.time.Instant - - -fun main(args: Array) { - //val z = doubleArrayOf(-1.736, -1.27, -0.754, -0.238, 0.278, 0.794, 1.31, 1.776) - //val b = doubleArrayOf(3.70754, 0.62786, 0.60474, 0.60325, 0.60333, 0.60503, 0.6285, 3.70478) - // System.out.println("Press any key to start..."); - // System.in.read(); - - val es = listOf(12000.0, 14000.0, 16000.0, 18000.0) - - val startTime = Instant.now() - System.out.printf("Starting at %s%n%n", startTime.toString()) - - for (e in es) { - SimulationManager().apply { - comment = "Out of the box cross-sections" - fileName = "trap[$e]" - setFields(0.6, 3.7, 7.2) - gasDensity = 1e19 - initialE = e - range = 4000.0 - }.simulateAll(1_000_000) - } - - val finishTime = Instant.now() - System.out.printf("%nFinished at %s%n", finishTime.toString()) - System.out.printf("Calculation took %s%n", Duration.between(startTime, finishTime).toString()) -} - +package ru.inr.mass.trapping + +import java.time.Duration +import java.time.Instant + + +fun main() { + //val z = doubleArrayOf(-1.736, -1.27, -0.754, -0.238, 0.278, 0.794, 1.31, 1.776) + //val b = doubleArrayOf(3.70754, 0.62786, 0.60474, 0.60325, 0.60333, 0.60503, 0.6285, 3.70478) + // System.out.println("Press any key to start..."); + // System.in.read(); + + val es = listOf(12000.0, 14000.0, 16000.0, 18000.0) + + val startTime = Instant.now() + System.out.printf("Starting at %s%n%n", startTime.toString()) + + for (e in es) { + SimulationManager().apply { + comment = "Out of the box cross-sections" + fileName = "trap[$e]" + setFields(0.6, 3.7, 7.2) + gasDensity = 1e19 + initialE = e + range = 4000.0 + }.simulateAll(1_000_000) + } + + val finishTime = Instant.now() + System.out.printf("%nFinished at %s%n", finishTime.toString()) + System.out.printf("Calculation took %s%n", Duration.between(startTime, finishTime).toString()) +} +