From 12a47e9bd4c090fea84205bfa0405bcab386c8e4 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 09:47:42 +0200 Subject: [PATCH 01/36] Added new particle emission SpaceIC "EmissionDistribution" for initial particle emission via interpolation of n, T and v from equidistant field data. --- .../2D-field-interpolation_mesh.h5 | Bin 0 -> 38503 bytes .../analyze.ini | 12 ++ .../command_line.ini | 1 + .../2D_variable_particle_init_n_T_v/hopr.ini | 43 +++++ .../parameter.ini | 111 ++++++++++++ .../2D_variable_particle_init_n_T_v/readme.md | 4 + ...reggie-linear-rot-symmetry-species-init.h5 | Bin 0 -> 5984 bytes src/io_hdf5/hdf5_input_field.f90 | 167 ++++++++++-------- .../emission/particle_emission_init.f90 | 86 ++++++++- .../emission/particle_emission_vars.f90 | 101 ++++++----- .../particle_mpi/particle_mpi_emission.f90 | 2 + .../pic/interpolation/pic_interpolation.f90 | 19 +- .../interpolation/pic_interpolation_vars.f90 | 2 +- 13 files changed, 410 insertions(+), 138 deletions(-) create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/2D-field-interpolation_mesh.h5 create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/hopr.ini create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/2D-field-interpolation_mesh.h5 b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/2D-field-interpolation_mesh.h5 new file mode 100644 index 0000000000000000000000000000000000000000..504bb9225a86677ba443e44057b937bcf4e6f0f8 GIT binary patch literal 38503 zcmeI53%r$8na00!KsW+&5lqC};ed(a1(g&p$p!@RhImKQ0ulj5Ak@56b}I9hrCFJk zdCN-8l+4uBjI@l>l$^$KtSOpo#+;h4(Z(s0o@cN1u-^6Vwefa1H8Xs_-+R`#{`+0e z^RD%+@7tR#950%>-;|B|4C_fV)-OgA0bw#*Cs+rNQUp2LU)>5@qL$JG#p0nh%`HL1-gWAV~@TgT|`&MID z$9>+?67CS)Cu-}d)vEFRkk6x~+MwzOy=imjEMk8k#Cr0iYOnunrX#(i)4Q&-aPopV zr=Ireb?S=@rv{xP=ASs{HR!C21vThQTlAWAI^**pt@lP@UPmpQ|E@FU#HwEX{AR4F zOV=;ci`Bh)y~pcUh1abY0!P$usYcabX=x2W>lz$EsJjpJzy> zzfQ{SSrK1zN%?hA++Ou#>INczU+pXHtChUaI8?sxzxI9AxoJ@B+$OZ)=ike|dZqQy z^CCWWE8p*d`-e-`>^Z%b`|Yi9J@#4qy3DgLuk-W9^$4Gc^gf~at9|YJp*lNGBEAEL zUgLh~T<3FrH3oy?WAVb6tk0q8eJH%YE}S?C?`Dn9TdiBXt?GM)d8zN8^Z9zGJdUcW z9`X4-81G}N(O=8{`cQp9Ju95?XX83+W+~_I;fx{$y)57>`r;-qP_PQ?d|iIa{zd-0sAqTa+=OU{1hoQ0?3qgB0s%$)gi z=bavA%hx9@I)g9Pf!2Lgc)97%#``6V(EGG>!e_2@-PM2X_s{BhT?b}0HD1@h&HMB# zt%u&1^*r_c*Z({na9&uDSNi-iFI%_uovvMh1(4I8*Jsl+d5oAvq zPR3fuRwATBc57tM7*2Kvf^3!HWcNh&qTyuA5MB%5J4 zSzBZ?4JYf5Ae(16*^tN<8%{P1L3WnmWbKi48cz0R1lfg#lkE`MWrmaOiXgkva5An9 z*|mm~?Hk#RhLhnBsukH%!^sYe>~6!!rX$Ff8BTU|WXlaFJ03x{!f>+Lkv(ZR**pZ< zO2f$(M)r*1WTzv@RvAuqPGm0{PR2DRt6J0kCp$l~Hp9s-L68kJoa}N0*-*pDu0)Wv z8%}mLf{fq!>b@hp0YNs#aI%{bWaA7cTZ$m78BTU5f^4ecWcMM+rW;Q70D^3W;bhAZ zWHSvXdlW%7&v3GzAjlRQPWBXn>@35{RwBqc5j}Ak&|P!zoD46mImG^gFU9+S?iOER z9z%!n^j!eC*q<<#n)(`s<9fx{^#@xr`(={GzKF3K;x+5bz7FNFHXULwU@Ud5Z$I=| zqxIcL1JP>iA260RTHgVMynzMwdyHkS_2oI&!1``n82dYnk; zdHuoYv2}cnbNVI5a{aAuJNn!o)|dJ^G>@NSYzLtA9ib$&${UPxdRgC}VJzoneMh3t z>t=noL0^aTp2ArASl?}xgjRV&an5ULeSeLy+>_RK6#Crz)^|Jfbx7|CjHQ#K9-DsQX?8ul>8PC?)L?v6h9p!MAYeI3$Uj#KR)^~68`OLDu`xM4Lh_Qpgt?#~tyzvFL0%PfEeQW6R8D@Papsz#oxF2H&0b1Wl zNESIpwC*Y@3H9XklvRtmhY|B_iai-tGr!tPJQcp1IAL{ z`ksJ3=V5){j=m1*U5BxJ-?P3mm4sG#$KjlFv%c40ET0M1cQ*RmFV^>+=+9tnX(rmUFYdC!x>%VtwbLuS0rQV(gZH)_1;=&?@g}oDW7=-!EV+ zuaWgV8GYWD*7p?jbx7}%7|YKl*7sB;p;g{Aob&#$zE@)`=VpBuqCXsAeHWpxLwc8C zEI&J0-*+hqt?~}UIiCmC_X>>VwY0uV(C23k>w6mdI;3~H09vs#3T!bL*U$Q19M{VF zz8g85hxI)ZeI4>RO8~9d*#))$jB~TT=fjtK()yl*KChegeGmFN9hbPAvq`#^!s1LHkoeb0q2?|tk0LG)RR_5Bd~I^=Pl z09vsR7uY+%c+XhhbKuMUXnik0za3$HFGOF5JkG?}Z2|3mzF0|UmA5_4`5Dgoo`JC) zVAl5%^mSw6jcBM^4JA4gw@d>3LY?>FoF z2_>Ob9F_!n1_5Dc9vA&-K(;>Z6Fm@Y2>wATg&?=AX*&AVf=VL7AW_>@6 zK69<_mFVk`-dv1*GobbTtdh_wk2!4!>$@0Zhl5$)&!Nv;>w6XYI;8h`0kmRQ7ue-s z^sv4kgD;;=*7q9pxlgU{wdm`R$8`c|#jY=~Pl0j$tnUeNt*q}Cki+X{eQ!WthdjP0 zfL82F1@;**UQ6pc2fo~s*7wWk^Zu~DH=?gY9ybY~6}!2>E&`*c^_>M@&dvIMr7-rE z0{d!#-CAHD18YZE-(%s+YiWINLw_{F&UY#LIyASh37{3by}-T>HU?pR4~8$FW7hW$ z^tVG;-*2F=LmqbupcT8T!0ray1z~-^S;)HwYzKt(y|<8eUx9tA!0rdz6=8i3!+be6 zJKt}kzazr>E<<03=Jp){v|}>u)ZslgjRV!#`!@A>$?ZWa_z0}-!Jr>yX|d7|Xq3eSe}Pw95NO zobQjYzT0Cg_qg?a0)5_Z*7u*#*CD;B7|VOm`aY>7w95NuoKHnq-=_+BKLX<#Sl^!( z@+QJ}G`RKsSt0LVzz#rI-<>d)bF=e3AANq-v%Wt^Ux()L3jwrZD+}zGVEZ7f?^f^~ z3ub-)6@AXZ`u+-i9rAcu0Ik@s3+&&(_C{FW&EWeMFzfs8=(85<`waRznQeVvMxXo7`mRP_hx9hV zSndPsTQ`e|%Hv;=9}i}I`(P~RW_??c$NSCt;_pMRIixoXW4Z6GZ_h&B24MRl&-%7v zEU%^YorV4;2THiMn@-_vVh&;Q_&%k$r^Bs!3 z8kqIntf1EezP$IX@32DN=3tYMXMLZB??GU8zFQ)X>tcPkD(L+tu9fxOx{%jiV86gv z)?$5!BaiE1eLD(ce;wD#`i>~%jV!RAV(cN#mw%Up`_KArTNwL0jO9MCzM~3x+ZEWa zFqU((^W7eKyx*+v=)&0NFqZq?`tt9&=-_Ej#Eu2_6vpyeT3lj=UXBi)avr0xpZVF$`tDZ98w++Q^6Y+o7{2_BX?@>< zJbvD_zPlInwuLW016$uc3VGweraRv~3we8i@y`|3cke>p2>9~zz4hIvkoQ)wY0mdC z%$IYs^W7JD2RYyI1--HG<>zecTPx&E06WXn0AH@D^_?8^>^e^==zTkmwZ8io@}?HpT^P%?x4zpTkIyjcdthPgeHhE@ zVSNuO+$cQ!M9aj!4l-TJGV)GzMq7x(px`}*r2hXDQhhbea*}3i+g=>uP>hT!}fi#Vf}NS^mCr{bKZUW(Ww?%zdq@D z<@;Ye)&J^r8m`Y8-?DzsTABMgrK>hpQ>pLk6!-e#USHQ;uS;Lt>x+AR@uZ($_oScm zq@VMopY!h1&#!x`Kj*3boTvJ8p6U-=&sDE4?)AmJzPQ)db@BS*USHhni+lYzyEXe! zeYIX+-0O>bea*|)FYfily}r17)NWi0XWmylJ>No}xc3#8F8&Q>{TSS!pYx=j^Q52i zq#w@uHR$I&>E}G@=REZIGx!du1(Mb$=Se^3Nk8X7jX!hV_4>g{*CpxaJk_7`RDaGx zFa2z*g>$bj?)AmJzIaj&XY20z27TREzJ76Ezqqeo+}E#pd3|xOFYfgd&mH8eR zb;SMiLA+U=dR_Xdp8S1W-0O>Xx4!m|uV37+kGQX2+}AJO_4@hqA?fEl)t~cJf6i0= zIq!P?uv7H>N%}cY_2)d*pYv3I&bwYetdHKml77xp{W(wddmif6Ppwb?nn-BHlTOb2 zyU))lUpl#O($9I)&w0|%d0L0yqy3-sbDs2bp7e8`^n(l zCDotvRDaG>{W(wd2d?L;*BAHt;$C0e>#w`(8|s&zuV38PFYfCXR~yvvxAkh_%nCj*H877-+#S+%2$P<6<=5S+CN@j+^>(guV37+ zk9gPX=g*C#pYv3I&Qtw4Pxa@#>-EF+)$=Fm=RDP)^HhJ%Q~f#bdi}6IdjC!OIZyTH zJk_6b-DjbC{0rgu{hptfxPLx~C*PnX?)CM(f!7!J`r=++-0N!|USHhni+g=>udjJ| zeQ~cZ?)AmJzP@kt`r=++-0O>bef7P*xYrl=`r>M}Ub-$`U)<}9dwubwpMUR{^mCr{ zbDs2b-hKLUg=(Qq_2)d*pYv3|=drJ*7EaRhA-)iKGoAE&@cFSH8?Beu7x((&USHg= zgRZ;R7x((&USB-v=hr>y=RE1>Jn84W`}FhclIqWSsz2wc{+y@!1J`rO>x+ARaj!4# z^>tmmzPQ&H_xj>qKhCc5`r=++-0O>bea*}3i+g=>uP>hT!@laM1?Qxn^Q52iq@VMo z-&z+Q(V(C6q@VMopY!h15Azz?P=C%-{W(wd=RDOP`0ytB;$C0e>x+B+jwbrzUSHhn zi+la{Ci>!DU)<}9dwtEz?@w{BFYfilz5Z5B>KFI=;$C0e>uX-VesQla?)Am>J{JBC zb5)5q^G)yXVZWt({kb*gUccG8iFo4x>7x((&Nx!w?F``y)s-&Ouq@VMopY!h159>U#q5hnw`g5M@&v~jpaP6zK zJ~{XLDL=pN;$FX_N&VtpU)m|XuP^TP#l60G z_vweahc?uo^HhJ%Q~fzl_2)dTPtM<{{;*om^ZMdmU)%zTK_b!oTukQ&XaG>lfGYvkf-;3U6-Wq z^YiCh$}j7r`g5H(s;_nP`r=++JgrZtM?9@hn1`MZNk8XFKj%q5=U#u^UEloqoa)bc zsz2wc{+#>z*WLOAUwuF9>lgR+i~IV;Q~mk8yuRL#yuP^C7f=8FIs^9qB4*KF=Up%dUp08C*MpK z?AM{plfKWFe$J)RcpdeM&oArvb<_L1RHU!F2!r z^uxSHHd!C>RKL$x{W(wd2j1*^4{@(A?w`-%USHR->#uL9zrD%&i2M4*ef{FTe$C6* zFYfily}r2D*K^hDi+g=>uP^TPH7~C(?)AmJzIe6f$k)G_Z+iat{Cs~l({HwJ;$C0e z&r5tw`SI6sG+Q@uuP^TP#l61f^}ls}I%;7?zJ77PKH`3T#Df}thW#Mk_4=)Ks}Z$& zWBz?*&Qtw4Pxa?KsPSjcQ~f!A{rX{jM%IF3($9I)&v~j}oGokP?<44e*Z|QB(T3<< z=x+$t2hk6~f4jU9qCa9FVgO+Y!F+^*Gnz2+p+w;q|ySBM@AhkqDo^4cMCzqY&F7wnJ=> z*a0ybu_Iz9#2CcRh+Po;9SHipJihPs_&Y3iM~p-4f$(~My?wr4FKY33s8DM!gzvLf z{{9`-x(~wlSv&uII{)qYz6jsvTJSILaV=^H-{;y)KyYm)BA7b~QA6mb1jZRa4lvae4lG`EP`uu9D;lIZHNxU@d(}vCm?t) zyd5zD@eTy{?o5Qw-wbRPg7?;JgkKM@w>5I!iD*Zhi12-{N9{QXYM+Gg>&aT@B3SD@ z1hwZQsC{yw@AWwMQxKf{0)*G&+)qW!L@Y%3{6%1k5lay7LY#&;9r13&8HN6tU}quD zL7a_v58}Oua}n=Dc)j<7bs|29_yEG^e+cY6#QBI1BYge^kzI(E8W$m`aWR6PA3;## z5(G7T{zt)B)5j2;-qio35@w9;tIs45WfFuuqzRt zMSKR~`=0~53UM{!^9bL+2JBkI^@!^bzVFxb3&^3y4G3y}5y3HELQuo^{d#^GIjr$U z1Z(zsH-T}EHzPP_pFaVNYcvrt1>y6z2V>4?1arQEV9qTFYWn_H!RT=-f;IX6ZD6c% zDS~tM{jY&>&bK4D2EPAwFs{KJ2=1wGAgFOCf|_?BIOc8yHGKb@VAQw=L5+J6tnoes zYxa8I0^=O-M{v$Qe>*U)(GG~w2%rCLFz(4^2=4LkAh@R=KyZ)y{)1rLeZF5WpZ^1lA^RbM8V@6=@d$#Re!X5P|3?_Z8XrY0L-_t< zV4U*`1lPd#e+5hIr#4{E~uG~vA>_w_X6(((DK z$8*)=x#qQD{AXUezRkGweZKTPSDl{6d36qQzRh^lX~>WDH1JqY18+7j?FV0{_JilG z@p^f#edu}IhYj^aodzCt8hA6ESbsx)tl#jK3P)#0jZM|SM>OHXoACBBueJ`nO6w4O zW4`B2^E;a8#5%oBXJeh=Yx^M$byoFb($&PrJg?tBx0Rpx+Vka`^7A?qZ#J*GerHE5jB|B%j%dQ; zJ~8VSbhJO6&YJz1>dEsRZ<;S(m%pZd&qvf6|99*|>r-uMsaH_{b(93t>y%&146T1< zIH-Mm{VOYekubJzHMai$f<(>+pd8uS+FBQAtAFu?aV?jAB1m+$MyYz!_`jv+ANKxs zN8@^osu$A|rc?EerD+nr-veLFapD8p!dHA%)m|Ubd|d|cPcb-VgeLxMT$jb!>)q8k zV%nkjZJ9mmUlq{v(vPg&d0c#X*@kP+3#*Dh;$WTDc7)xCKZ5pNTh{v5)~~?&6sR3Qt-z}I=i&8jSikk_&|T{=FK*aJVmm*!r^S|ExA8bRH1+>fz*Bx5$72D4pH1J* K4i0_|$K$UyWhe{) literal 0 HcmV?d00001 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini new file mode 100644 index 000000000..b69af198d --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini @@ -0,0 +1,12 @@ +! ! hdf5 diff +! h5diff_file = TE28_8_PIC-EMField.h5 +! h5diff_reference_file = TE28_8_PIC-EMField_ref.h5 +! h5diff_data_set = DG_Solution\sDG_Solution ! data set name in h5diff_file and h5diff_reference_file +! h5diff_tolerance_value = 1.0e-10 +! h5diff_tolerance_type = relative +! +! ! PartAnalyze.csv diff +! compare_data_file_name = PartAnalyze.csv +! compare_data_file_reference = PartAnalyze-ref.csv +! compare_data_file_tolerance = 2e-2 +! compare_data_file_tolerance_type = relative diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini new file mode 100644 index 000000000..4b20f5225 --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini @@ -0,0 +1 @@ +MPI=1,2 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/hopr.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/hopr.ini new file mode 100644 index 000000000..1d2d46d79 --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/hopr.ini @@ -0,0 +1,43 @@ +!=============================================================================== ! +! MAKEFILE PARAMETER (put a "#" in front, NO blanks!) +!=============================================================================== ! +! This is only a dummy parameter needed for the regression check +#MPI= + +!=============================================================================== ! +! OUTPUT +!=============================================================================== ! + ProjectName =2D-field-interpolation ! name of the project (used for filenames) + Debugvisu =F ! Write debug mesh to tecplot file + Logging =F ! Write log files + +!=============================================================================== ! +! MESH +!=============================================================================== ! + Mode =1 ! 1 Cartesian 2 gambit file 3 CGNS + nZones =1 ! number of zones + Corner =(/0.,0.,0.,, 5.,0.,0.,, 5.,0.001,0.,, 0.,0.001,0. ,, 0.,0.,10.,, 5.,0.,10.,, 5.,0.001,10.,, 0.,0.001,10. /) ! [0,1]x[0,1]x[0,0.05] + nElems =(/4,1,20/) ! Anzahl der Elemente in jede Richtung (nfine 4:15 5:32 5:54 7:128) + BCIndex =(/1,1,1,1,1,1/) ! Indices of UserDefinedBoundaries + elemtype =108 ! Elementform (108: Hexaeder) + useCurveds =F ! T if curved boundaries defined + SpaceQuandt =1. ! characteristic length of the mesh + ConformConnect=T + +!=============================================================================== ! +! BOUNDARY CONDITIONS +!=============================================================================== ! + nUserDefinedBoundaries=1 + BoundaryName=BC_absorbing ! Outflow: open (absorbing) [for MAXWELL] + BoundaryType=(/4,0,0,0/) ! Outflow: open (absorbing) [for MAXWELL] + +!=============================================================================== ! +! BASIS +!=============================================================================== ! + NVisu = 7 + +!=============================================================================== ! +! SEARCH +!=============================================================================== ! +! nElemsNodeSearch=50 +! RefineSideSearch=50 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini new file mode 100644 index 000000000..ac38039c5 --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini @@ -0,0 +1,111 @@ +! =============================================================================== ! +! EQUATION (linearscalaradvection) +! =============================================================================== ! +IniExactFunc = 0 + +! =============================================================================== ! +! DISCRETIZATION +! =============================================================================== ! +N = 1 ! Polynomial degree +NAnalyze = 8 ! Number of analyze points + +! =============================================================================== ! +! MESH +! =============================================================================== ! +MeshFile = 2D-field-interpolation_mesh.h5 +useCurveds = F +! =============================================================================== ! +! OUTPUT / VISUALIZATION +! =============================================================================== ! +ProjectName = TE28_8 +Logging = F +WriteErrorFiles = F +printRandomSeeds = F +DoCalcErrorNorms = F +TrackingMethod = refmapping!,tracing,triatracking + +!CheckExchangeProcs = F ! deactivate the asymmetric communicator check +! =============================================================================== ! +! CALCULATION +! =============================================================================== ! +tend = 1.0E-12 +Analyze_dt = 1.0E-12 +CFLscale = 0.9 ! Scaling of theoretical CFL number +c_corr = 1 + +CalcMeshInfo=T +CalcHaloInfo=T +CalcEMFieldOutput=T +!Particles-HaloEpsVelo=1e9 + +! =============================================================================== ! +! Load Balance +! =============================================================================== ! +DoLoadBalance = T +DoInitialAutoRestart = T +Load-DeviationThreshold = 1e-9 +LoadBalanceMaxSteps = 2 +Particles-MPIWeight = 0.01 + +! =============================================================================== ! +! PARTICLES +! =============================================================================== ! +Part-maxParticleNumber = 15000 +Part-nSpecies = 1 +Part-nBounds = 1 +Part-Boundary1-SourceName = BC_absorbing +Part-Boundary1-Condition = reflective + +PIC-Interpolation-Type = particle_position + +PIC-Deposition-Type = shape_function +PIC-shapefunction-radius = 0.85 +PIC-shapefunction-dimension = 2 +PIC-shapefunction-direction = 2 +PIC-shapefunction-alpha = 4 + +Part-FIBGMdeltas = (/0.5,0.001,.5/) + +Part-FileNameEmissionDistribution = reggie-linear-rot-symmetry-species-init.h5 + +! =============================================================================== ! +! Species1 - electrons +! =============================================================================== ! +Part-Species1-ChargeIC = -1.60217653E-19 +Part-Species1-MassIC = 9.1093826E-31 +Part-Species1-MacroParticleFactor = 1E6 + +Part-Species1-nInits = 1 + +Part-Species1-Init1-SpaceIC = EmissionDistribution +Part-Species1-Init1-EmissionDistributionName = electron + +! =============================================================================== ! +! Species3 | HeIon +! =============================================================================== ! +Part-Species2-ChargeIC = 1.60217653E-19 +Part-Species2-MassIC = 6.645565470903E-027 +Part-Species2-MacroParticleFactor = 1E6 + +Part-Species2-nInits = 1 + +Part-Species2-Init1-SpaceIC = EmissionDistribution +Part-Species2-Init1-EmissionDistributionName = HeIon + + +! =============================================================================== ! +! Analysis +! =============================================================================== ! +Part-AnalyzeStep = 1 +CalcKineticEnergy = T +CalcPartBalance = T +CalcCharge = F +CalcPotentialEnergy = T +CalcNumSpec = T +Part-NumberOfRandomSeeds = 2 +Particles-RandomSeed1 = 1180520427 +Particles-RandomSeed2 = 1708457652 +PIC-OutputSource = T ! HDF5 output of maxwell source terms +PIC-VerifyCharge = F +NVisu=4 +VisuParticles=T diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md new file mode 100644 index 000000000..7424e101e --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md @@ -0,0 +1,4 @@ +# 2D Variable Emission Distribution +- Read particle emission initialization info from reggie-linear-rot-symmetry-species-init.h5 + - n, T, vx, vy, vz for different species + - Transformation from Cartesian coordinates to cylinder coordinates due to function v(r,z) diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 new file mode 100644 index 0000000000000000000000000000000000000000..0c068c39a9b41c7961bc3e9f7f054aed95c23d2c GIT binary patch literal 5984 zcmeHLziU)M5T18u;t@}|NHjqNk5^eq&=UoVykH_JL?s3k6ul#c7zqi4AW0fe{6Vye zrJapn>7O9@4+u6E3PPF`22u(Zadv0sUb5coz9%6TW{aEMnQvxi=XSqc-iwi;O9#7- zb%AN666}MD?aI$4w|XyWWGwbNcOsU{EZ-HV6Tu-cwm#NZIDWNAiks{>Haa{Eh?Mvu z*$tLEsF#RhPySaG7#SYCW)}ROS8WGoe3TU|?ltBcrfcMBmSSAa5l%~>=+r36+FP_>#Uq7Ba5yfu%E-8f4*^FH2x6^&@T&sevWvOWi}B(C)I-EL_q#gffPL)#?;s}cU;7p z8)SEN0I=lP5~v-3+9oI5fm&lP6ewVc|Jh>1aA->DtoLD78=qG{)*Ar#t$w$Du3x!2 zWcHF&aX}WYB#^MaLVvr0+EedUAWH={1_;%Yko@^*yA*q00v|qoKKu6NMQgwOjqzeX z9z%bOZIlWg&c}@typAg41}<#cBNK;_#fbB{NkK`kWi!`|5#YMKJg3kk>VHRC&drz;^!;HFV5*F zJQdX?`KT)BLb5UjEbk;+%fMXCZ!c=M%pWUuu3K{?z=iE?z#>{Nl`h z>HD{6zau?dpqN?Tzw&PVBhF&JIGqH?9OSze=d+YAj@$#lU!cs`d><1DaNY)-o24&N eS=Y(wwZz|k=bM#fK;+xZPYYzW~1 literal 0 HcmV?d00001 diff --git a/src/io_hdf5/hdf5_input_field.f90 b/src/io_hdf5/hdf5_input_field.f90 index 97b8239c2..bbd210d1c 100644 --- a/src/io_hdf5/hdf5_input_field.f90 +++ b/src/io_hdf5/hdf5_input_field.f90 @@ -26,55 +26,69 @@ MODULE MOD_HDF5_Input_Field ! Private Part --------------------------------------------------------------------------------------------------------------------- ! Public Part ---------------------------------------------------------------------------------------------------------------------- #if defined(PARTICLES) -PUBLIC :: ReadVariableExternalFieldFromHDF5 +PUBLIC :: ReadExternalFieldFromHDF5 #endif /*defined(PARTICLES)*/ !=================================================================================================================================== CONTAINS #if defined(PARTICLES) -SUBROUTINE ReadVariableExternalFieldFromHDF5() +SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField, FileNameExternalField, ExternalFieldDim, & + ExternalFieldAxisSym, ExternalFieldRadInd, ExternalFieldAxisDir, ExternalFieldMin, ExternalFieldMax, ExternalFieldN) !=================================================================================================================================== -!> Read-in of spatially variable external magnetic field from .h5 file +!> Read-in of spatially variable external magnetic field or macroscopic species data (n, T, vx, vy and vz) from .h5 file !> Check for different fields in the file: x,y,z or x,r or y,r or z,r to determine a possible axial symmetry -!> as well as Bx, By, Bz or Br, Bz etc. +!> as well as +!> a) Bx, By, Bz or Br, Bz etc. (magnetic fields) +!> b) vx, vy, vz or vr, vz etc. (macroscopic data) !=================================================================================================================================== ! use module !USE MOD_IO_HDF5 USE MOD_Globals !USE MOD_HDF5_Input ,ONLY: DatasetExists,ReadAttribute -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalField,DeltaExternalField,FileNameVariableExternalField -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldDim,VariableExternalFieldAxisSym,VariableExternalFieldRadInd -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldAxisDir -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldMin,VariableExternalFieldMax,VariableExternalFieldN ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- ! INPUT VARIABLES +CHARACTER(LEN=*),INTENT(IN) :: DataSet !< dataset name to read from .h5 +CHARACTER(LEN=255),INTENT(IN) :: FileNameExternalField !< data read from .h5 !----------------------------------------------------------------------------------------------------------------------------------- ! OUTPUT VARIABLES +REAL,ALLOCATABLE,INTENT(OUT) :: ExternalField(:,:) !< array to be read +REAL,INTENT(OUT) :: DeltaExternalField(3) !< dx, dy, dz +INTEGER,INTENT(OUT) :: ExternalFieldDim !< Dimension of the data (1D, 2D or 3D) +LOGICAL,INTENT(OUT) :: ExternalFieldAxisSym !< Flag for setting axisymmetric data +INTEGER,INTENT(OUT) :: ExternalFieldRadInd !< Index of radial r-coordinate when using 2D data and axis symmetric +INTEGER,INTENT(OUT) :: ExternalFieldAxisDir !< Direction that is used for the axial symmetric direction (1,2 or 3) +REAL,INTENT(OUT) :: ExternalFieldMin(1:3) !< Minimum values in x,y,z +REAL,INTENT(OUT) :: ExternalFieldMax(1:3) !< Maximum values in x,y,z +INTEGER,INTENT(OUT) :: ExternalFieldN(1:3) !< Number of points in x, y and z-direction !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -CHARACTER(LEN=64) :: dsetname,AttributeName -INTEGER :: err -INTEGER :: NbrOfRows,NbrOfColumns,iDir,j -INTEGER(HSIZE_T), DIMENSION(2) :: dims,sizeMax -INTEGER(HID_T) :: file_id_loc ! File identifier -INTEGER(HID_T) :: dset_id_loc ! Dataset identifier -INTEGER(HID_T) :: filespace ! filespace identifier -LOGICAL :: DatasetFound,AttribtueFound -REAL :: delta,deltaOld -INTEGER :: iDirMax +CHARACTER(LEN=64) :: dsetname,AttributeName +INTEGER :: err +INTEGER :: NbrOfRows,NbrOfColumns,iDir,j +INTEGER(HSIZE_T), DIMENSION(2) :: dims,sizeMax +INTEGER(HID_T) :: file_id_loc ! File identifier +INTEGER(HID_T) :: dset_id_loc ! Dataset identifier +INTEGER(HID_T) :: filespace ! filespace identifier +LOGICAL :: DatasetFound,AttribtueFound +REAL :: delta,deltaOld +INTEGER :: iDirMax !=================================================================================================================================== +! Defaults +ExternalFieldDim = 1 ! default is 1D +ExternalFieldAxisSym = .FALSE. + ! Initialize FORTRAN interface. CALL H5OPEN_F(err) ! Open the file. -CALL H5FOPEN_F(TRIM(FileNameVariableExternalField), H5F_ACC_RDONLY_F, file_id_loc, err) +CALL H5FOPEN_F(TRIM(FileNameExternalField), H5F_ACC_RDONLY_F, file_id_loc, err) ! Check if the datasets exist DatasetFound = .FALSE. -dsetname = TRIM('/data') +dsetname = TRIM('/'//DataSet) CALL H5LEXISTS_F(file_id_loc, TRIM(dsetname), DatasetFound, err) IF(DatasetFound) THEN ! Open the dataset. @@ -86,128 +100,129 @@ SUBROUTINE ReadVariableExternalFieldFromHDF5() ! Flip columns and rows between .h5 data and Fortran data NbrOfColumns = INT(dims(2)) ! this is the total number of points NbrOfRows = INT(dims(1)) ! this is the number of properties x,y,z,Bx,By,Bz + WRITE (*,*) "NbrOfColumns,NbrOfRows =", NbrOfColumns,NbrOfRows ! Read-in the data - ALLOCATE(VariableExternalField(1:NbrOfRows,1:NbrOfColumns)) - VariableExternalField=0. + ALLOCATE(ExternalField(1:NbrOfRows,1:NbrOfColumns)) + ExternalField=0. ! read data - CALL H5DREAD_F(dset_id_loc, H5T_NATIVE_DOUBLE, VariableExternalField(1:NbrOfRows,1:NbrOfColumns), dims, err) -ELSE - CALL abort(__STAMP__,'Dataset "'//TRIM(dsetname)//'" not found in '//TRIM(FileNameVariableExternalField)) -END IF - -! Set spatial dimension -IF(NbrOfRows.LT.6)THEN - VariableExternalFieldDim = 2 + CALL H5DREAD_F(dset_id_loc, H5T_NATIVE_DOUBLE, ExternalField(1:NbrOfRows,1:NbrOfColumns), dims, err) ELSE - VariableExternalFieldDim = 3 + CALL abort(__STAMP__,'Dataset "'//TRIM(dsetname)//'" not found in '//TRIM(FileNameExternalField)) END IF ! Check for radial component -VariableExternalFieldRadInd = -1 -VariableExternalFieldAxisSym = .FALSE. +ExternalFieldRadInd = -1 +ExternalFieldAxisSym = .FALSE. AttributeName = 'r' CALL H5AEXISTS_F(file_id_loc, TRIM(AttributeName), AttribtueFound, iError) -IF(AttribtueFound) CALL ReadAttribute(file_id_loc,AttributeName,1,IntScalar=VariableExternalFieldRadInd) -IF(VariableExternalFieldRadInd.GT.0) VariableExternalFieldAxisSym=.TRUE. +IF(AttribtueFound) CALL ReadAttribute(file_id_loc,AttributeName,1,IntScalar=ExternalFieldRadInd) +IF(ExternalFieldRadInd.GT.0) ExternalFieldAxisSym=.TRUE. + +! Set spatial dimension +IF(ExternalFieldAxisSym)THEN + ExternalFieldDim = 2 +ELSE + ExternalFieldDim = 3 +END IF ! ExternalFieldAxisSym ! Check if axial symmetric and 2D -IF(VariableExternalFieldDim.EQ.2)THEN - IF(.NOT.VariableExternalFieldAxisSym) CALL abort(__STAMP__,'Only 2D axis symmetric variable external field imeplemented.') +IF(ExternalFieldDim.EQ.2)THEN + IF(.NOT.ExternalFieldAxisSym) CALL abort(__STAMP__,'Only 2D axis symmetric external field imeplemented.') ELSE ! 3D and symmetric is not possible - VariableExternalFieldAxisSym = .FALSE. -END IF ! VariableExternalFieldDim.EQ.2 + ExternalFieldAxisSym = .FALSE. +END IF ! ExternalFieldDim.EQ.2 -! Check for axial direction when using axis symmetric variable external field -IF(VariableExternalFieldAxisSym)THEN - VariableExternalFieldAxisDir=-1 +! Check for axial direction when using axis symmetric external field +IF(ExternalFieldAxisSym)THEN + ExternalFieldAxisDir=-1 ! Check z-dir AttributeName = 'z' CALL H5AEXISTS_F(file_id_loc, TRIM(AttributeName), AttribtueFound, iError) - IF(AttribtueFound) CALL ReadAttribute(file_id_loc,AttributeName,1,IntScalar=VariableExternalFieldAxisDir) - IF(VariableExternalFieldAxisDir.GT.0) VariableExternalFieldAxisDir=3 + IF(AttribtueFound) CALL ReadAttribute(file_id_loc,AttributeName,1,IntScalar=ExternalFieldAxisDir) + IF(ExternalFieldAxisDir.GT.0) ExternalFieldAxisDir=3 ! Check if not axial symmetric with z-direction - IF(VariableExternalFieldAxisDir.NE.3) CALL abort(__STAMP__,'Only z-axis symmetric variable external field imeplemented currently.') -END IF ! VariableExternalFieldAxisSym + IF(ExternalFieldAxisDir.NE.3) CALL abort(__STAMP__,'Only z-axis symmetric external field imeplemented currently.') +END IF ! ExternalFieldAxisSym ! Calculate the deltas and make sure that they are equidistant -DeltaExternalField = -1.0 -VariableExternalFieldMin = HUGE(1.) -VariableExternalFieldMax = -HUGE(1.) -VariableExternalFieldN(1:3) = -1 -IF(VariableExternalFieldDim.EQ.2)THEN +DeltaExternalField = -1.0 +ExternalFieldMin = HUGE(1.) +ExternalFieldMax = -HUGE(1.) +ExternalFieldN(1:3) = -1 +IF(ExternalFieldDim.EQ.2)THEN ! 2D field iDirMax = 2 - VariableExternalFieldMin(3) = 0. - VariableExternalFieldMax(3) = 0. + ExternalFieldMin(3) = 0. + ExternalFieldMax(3) = 0. DeltaExternalField(3) = 0. ELSE ! 3D field iDirMax = 3 -END IF ! VariableExternalFieldDim.EQ.2 +END IF ! ExternalFieldDim.EQ.2 ! Loop x, y and z-coordinate and check deltas between points DO iDir = 1, iDirMax ! Get global min/max - VariableExternalFieldMin(iDir) = MINVAL(VariableExternalField(iDir,:)) - VariableExternalFieldMax(iDir) = MAXVAL(VariableExternalField(iDir,:)) + ExternalFieldMin(iDir) = MINVAL(ExternalField(iDir,:)) + ExternalFieldMax(iDir) = MAXVAL(ExternalField(iDir,:)) deltaOld = -1.0 DO j = 1, NbrOfColumns-1 - delta = VariableExternalField(iDir,j+1)-VariableExternalField(iDir,j) + delta = ExternalField(iDir,j+1)-ExternalField(iDir,j) !write(*,*) delta IF((deltaOld.GT.0.).AND.(delta.GT.0.))THEN !WRITE (*,*) "delta,deltaOld =", iDir,j,delta,deltaOld - IF(.NOT.ALMOSTEQUALRELATIVE(delta,deltaOld,1e-5)) CALL abort(__STAMP__,'Variable external field: not equidistant.') + IF(.NOT.ALMOSTEQUALRELATIVE(delta,deltaOld,1e-5)) CALL abort(__STAMP__,'External field: not equidistant.') END IF ! deltaOld.GT.0. ! Backup old value IF(delta.GT.0.)THEN deltaOld = delta DeltaExternalField(iDir) = delta ELSEIF(delta.LT.0.)THEN - IF(VariableExternalFieldDim.EQ.2)THEN - IF(VariableExternalFieldN(1).LT.0)THEN + IF(ExternalFieldDim.EQ.2)THEN + IF(ExternalFieldN(1).LT.0)THEN ! z-dir - VariableExternalFieldN(1) = j + ExternalFieldN(1) = j ! r-dir - VariableExternalFieldN(2) = NbrOfColumns/VariableExternalFieldN(1) + ExternalFieldN(2) = NbrOfColumns/ExternalFieldN(1) END IF ELSE - IF(VariableExternalFieldN(iDir).LT.0)THEN + IF(ExternalFieldN(iDir).LT.0)THEN IF(iDir.EQ.1)THEN - VariableExternalFieldN(iDir) = j + ExternalFieldN(iDir) = j ELSE - VariableExternalFieldN(2) = j / VariableExternalFieldN(1) - VariableExternalFieldN(3) = NbrOfColumns/(VariableExternalFieldN(1)*VariableExternalFieldN(2)) + ExternalFieldN(2) = j / ExternalFieldN(1) + ExternalFieldN(3) = NbrOfColumns/(ExternalFieldN(1)*ExternalFieldN(2)) END IF - END IF ! VariableExternalFieldN(iDir).LT.0 - END IF ! VariableExternalFieldDim.EQ.2 + END IF ! ExternalFieldN(iDir).LT.0 + END IF ! ExternalFieldDim.EQ.2 END IF END DO ! j = 1, NbrOfColumns END DO ! iDir = 1, iDirMax ! Sanity check -ASSOCIATE( x => VariableExternalFieldN(1:3) ) - IF(VariableExternalFieldDim.EQ.2)THEN - IF(MINVAL(DeltaExternalField(1:2)).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for variable external field.') +ASSOCIATE( x => ExternalFieldN(1:3) ) + IF(ExternalFieldDim.EQ.2)THEN + IF(MINVAL(DeltaExternalField(1:2)).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for external field.') ! z-dir: x(1) ! r-dir: x(2) IF(NbrOfColumns.NE.x(1)*x(2)) CALL abort(__STAMP__,'Wrong number of points in 2D') SWRITE (UNIT_stdOut,'(A,2(I0,A))') " Read external field with ",x(1)," x ",x(2)," data points" ELSE - IF(MINVAL(DeltaExternalField).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for variable external field.') + IF(MINVAL(DeltaExternalField).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for external field.') IF(NbrOfColumns.NE.x(1)*x(2)*x(3)) CALL abort(__STAMP__,'Wrong number of points in 3D') SWRITE (UNIT_stdOut,'(A,3(I0,A))') " Read external field with ",x(1)," x ",x(2)," x ",x(3)," data points" - END IF ! VariableExternalFieldDim.EQ.2 + END IF ! ExternalFieldDim.EQ.2 END ASSOCIATE -!WRITE (*,*) " =", VariableExternalFieldMin -!WRITE (*,*) " =", VariableExternalFieldMax +!WRITE (*,*) " =", ExternalFieldMin +!WRITE (*,*) " =", ExternalFieldMax ! Close the file. CALL H5FCLOSE_F(file_id_loc, err) ! Close FORTRAN interface. CALL H5CLOSE_F(err) -END SUBROUTINE ReadVariableExternalFieldFromHDF5 +END SUBROUTINE ReadExternalFieldFromHDF5 #endif /*defined(PARTICLES)*/ END MODULE MOD_HDF5_Input_Field diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index aa81fe26e..21f05be16 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -146,9 +146,7 @@ SUBROUTINE DefineParametersParticleEmission() 'Height of excluded cylinder, if'//& ' Part-Species[$]-Init[$]-ExcludeRegion[$]-SpaceIC=cylinder (set 0 for flat circle),'//& 'negative value = opposite direction ', '1.', numberedmulti=.TRUE.) -CALL prms%CreateStringOption( 'Part-Species[$]-Init[$]-NeutralizationSource' & - , 'Name of the boundary used for calculating the charged particle balance used for thruster'//& - ' neutralization (no default).' ,numberedmulti=.TRUE.) +CALL prms%CreateStringOption( 'Part-Species[$]-Init[$]-NeutralizationSource' , 'Name of the boundary used for calculating the charged particle balance used for thruster neutralization (no default).' ,numberedmulti=.TRUE.) ! ====================================== photoionization ================================================================= CALL prms%CreateLogicalOption('Part-Species[$]-Init[$]-FirstQuadrantOnly','Only insert particles in the first quadrant that is'//& ' spanned by the vectors x=BaseVector1IC and y=BaseVector2IC in the interval x,y in [0,R]', '.FALSE.', numberedmulti=.TRUE.) @@ -169,6 +167,9 @@ SUBROUTINE DefineParametersParticleEmission() ' Different weighting factor can be used', '.FALSE.', numberedmulti=.TRUE.) CALL prms%CreateIntOption( 'Part-Species[$]-Init[$]-PartBCIndex','Associated particle boundary ID','-1',numberedmulti=.TRUE.) CALL prms%CreateRealOption('Part-Species[$]-Init[$]-MacroParticleFactor', 'Emission-specific particle weighting factor: number of simulation particles per real particle',numberedmulti=.TRUE.) +! ====================================== emission distribution ================================================================= +CALL prms%CreateStringOption( 'Part-Species[$]-Init[$]-EmissionDistributionName' , 'Name of the species, e.g., "electron" or "ArIon" used for initial emission via interpolation of n, T and v from equidistant field data (no default).' ,numberedmulti=.TRUE.) +CALL prms%CreateStringOption( 'Part-FileNameEmissionDistribution' , 'H5 or CSV file containing the data for initial emission via interpolation of n, T and v from equidistant field data', 'none') END SUBROUTINE DefineParametersParticleEmission @@ -181,11 +182,12 @@ SUBROUTINE InitializeVariablesSpeciesInits() USE MOD_Globals_Vars USE MOD_ReadInTools USE MOD_Particle_Vars -USE MOD_DSMC_Vars ,ONLY: useDSMC, BGGas -USE MOD_DSMC_BGGas ,ONLY: BGGas_Initialize +USE MOD_DSMC_Vars ,ONLY: useDSMC, BGGas +USE MOD_DSMC_BGGas ,ONLY: BGGas_Initialize #if USE_MPI -USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance #endif /*USE_MPI*/ +USE MOD_Restart_Vars ,ONLY: DoRestart ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- @@ -200,6 +202,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() ALLOCATE(SpecReset(1:nSpecies)) SpecReset=.FALSE. UseNeutralization = .FALSE. +UseEmissionDistribution = .FALSE. ! Background gas BGGas%NumberOfSpecies = 0 ALLOCATE(BGGas%BackgroundSpecies(nSpecies)) @@ -359,8 +362,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() ! 2D simulation/variable time step only with cell_local and/or surface flux IF((Symmetry%Order.EQ.2).OR.VarTimeStep%UseVariableTimeStep) THEN IF (TRIM(Species(iSpec)%Init(iInit)%SpaceIC).NE.'cell_local') THEN - CALL abort(__STAMP__& - ,'ERROR: Particle insertion/emission for 2D/axisymmetric or variable time step only possible with'//& + CALL abort(__STAMP__,'ERROR: Particle insertion/emission for 2D/axisymmetric or variable time step only possible with'//& 'cell_local-SpaceIC and/or surface flux!') END IF END IF @@ -416,6 +418,11 @@ SUBROUTINE InitializeVariablesSpeciesInits() IF(.NOT.DoPoissonRounding .AND. .NOT.DoTimeDepInflow) CALL CollectiveStop(__STAMP__, & ' Linearly ramping of inflow-number-of-particles is only possible with PoissonRounding or DoTimeDepInflow!') END IF + !--- Emission distribution + IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN + UseEmissionDistribution = .TRUE. + Species(iSpec)%Init(iInit)%EmissionDistributionName = TRIM(GETSTR('Part-Species'//TRIM(hilf2)//'-EmissionDistributionName')) + END IF ! TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution' END DO ! iInit END DO ! iSpec IF(nSpecies.GT.0)THEN @@ -436,6 +443,14 @@ SUBROUTINE InitializeVariablesSpeciesInits() END IF ! BGGas%NumberOfSpecies.GT.0 END IF !useDSMC +!-- Read Emission Distribution stuff +IF(UseEmissionDistribution.AND.(.NOT.DoRestart)) THEN + FileNameEmissionDistribution = GETSTR('Part-FileNameEmissionDistribution') + CALL ReadUseEmissionDistribution() +END IF +!SWRITE (*,*) "BARRIER =" +!IF(myrank.eq.0) read*; CALL MPI_BARRIER(MPI_COMM_WORLD,iError) + END SUBROUTINE InitializeVariablesSpeciesInits @@ -989,4 +1004,59 @@ SUBROUTINE InitializeEmissionSpecificMPF() END SUBROUTINE InitializeEmissionSpecificMPF + +SUBROUTINE ReadUseEmissionDistribution() +!=================================================================================================================================== +! ATTENTION: The fields (density, temperature and velocity) need to be defined on equidistant data-points as either .csv or .h5 file +!=================================================================================================================================== +! MODULES +USE MOD_Globals +USE MOD_Particle_Emission_Vars ,ONLY: FileNameEmissionDistribution +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim,EmissionDistributionAxisSym +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution,EmissionDistributionDelta,EmissionDistributionDim +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionRadInd,EmissionDistributionAxisDir +USE MOD_HDF5_Input_Field ,ONLY: ReadExternalFieldFromHDF5 +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ +! IMPLICIT VARIABLE HANDLING + IMPLICIT NONE +!---------------------------------------------------------------------------------------------------------------------------------- +! INPUT VARIABLES +!---------------------------------------------------------------------------------------------------------------------------------- +! OUTPUT VARIABLES +!---------------------------------------------------------------------------------------------------------------------------------- +! LOCAL VARIABLES +INTEGER,PARAMETER :: lenmin=4 +INTEGER :: lenstr +!=================================================================================================================================== +LBWRITE(UNIT_stdOut,'(A,3X,A,65X,A)') ' INITIALIZATION OF EMISSION DISTRIBUTION FOR PARTICLES ' + +! Check if file exists +IF(.NOT.FILEEXISTS(FileNameEmissionDistribution)) CALL abort(__STAMP__,"File not found: "//TRIM(FileNameEmissionDistribution)) + +! Check length of file name +lenstr=LEN(TRIM(FileNameEmissionDistribution)) +IF(lenstr.LT.lenmin) CALL abort(__STAMP__,"File name too short: "//TRIM(FileNameEmissionDistribution)) + +! Check file ending, either .csv or .h5 +IF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+2:lenstr)).EQ.'.h5')THEN + CALL ReadExternalFieldFromHDF5('electron',& + EmissionDistribution , EmissionDistributionDelta , FileNameEmissionDistribution , EmissionDistributionDim , & + EmissionDistributionAxisSym , EmissionDistributionRadInd , EmissionDistributionAxisDir , EmissionDistributionMin , & + EmissionDistributionMax , EmissionDistributionN) +ELSEIF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+1:lenstr)).EQ.'.csv')THEN + CALL abort(__STAMP__,'ReadUseEmissionDistribution(): Read-in from .csv is not implemented') +ELSE + CALL abort(__STAMP__,"Unrecognised file format for : "//TRIM(FileNameEmissionDistribution)) +END IF + +IF(.NOT.ALLOCATED(EmissionDistribution)) CALL abort(__STAMP__,"Failed to load data from: "//TRIM(FileNameEmissionDistribution)) + +LBWRITE(UNIT_stdOut,'(A)')' ...EMISSION DISTRIBUTION INITIALIZATION DONE' +END SUBROUTINE ReadUseEmissionDistribution + + END MODULE MOD_Particle_Emission_Init diff --git a/src/particles/emission/particle_emission_vars.f90 b/src/particles/emission/particle_emission_vars.f90 index fc4d20eae..e078ad93f 100644 --- a/src/particles/emission/particle_emission_vars.f90 +++ b/src/particles/emission/particle_emission_vars.f90 @@ -44,51 +44,51 @@ MODULE MOD_Particle_Emission_Vars TYPE tInit ! Particle Data for each init emission for each species !Specific Emission/Init values - CHARACTER(40) :: SpaceIC ! specifying Keyword for Particle Space condition - CHARACTER(30) :: velocityDistribution ! specifying keyword for velocity distribution - REAL :: Area ! Area for IC Rectangle - REAL :: RadiusIC ! Radius for IC circle - REAL :: Radius2IC ! Radius2 for IC cylinder (ring) - REAL :: RadiusICGyro ! Radius for Gyrotron gyro radius - REAL :: InflowRiseTime ! time to ramp the number of inflow particles - ! linearly from zero to unity - REAL :: NormalIC(3) ! Normal / Orientation of circle - REAL :: BasePointIC(3) ! base point for IC cuboid and IC sphere - REAL :: BaseVector1IC(3) ! first base vector for IC cuboid - REAL :: NormalVector1IC(3) ! 1st base vector normalized - REAL :: BaseVector2IC(3) ! second base vector for IC cuboid - REAL :: NormalVector2IC(3) ! 2nd base vector normalized - REAL :: CuboidHeightIC ! third measure of cuboid - ! (set 0 for flat rectangle), - ! negative value = opposite direction - REAL :: CylinderHeightIC ! third measure of cylinder - ! (set 0 for flat rectangle), - ! negative value = opposite direction - REAL :: VeloIC ! velocity for inital Data - REAL :: VeloVecIC(3) ! normalized velocity vector - REAL :: Amplitude ! Amplitude for sin-deviation initiation. - REAL :: WaveNumber ! WaveNumber for sin-deviation initiation. - INTEGER :: maxParticleNumberX ! Maximum Number of all Particles in x direction - INTEGER :: maxParticleNumberY ! Maximum Number of all Particles in y direction - INTEGER :: maxParticleNumberZ ! Maximum Number of all Particles in z direction - REAL :: Alpha ! WaveNumber for sin-deviation initiation. - REAL :: MWTemperatureIC ! Temperature for Maxwell Distribution - REAL :: PartDensity ! PartDensity (real particles per m^3) - INTEGER :: ParticleEmissionType ! Emission Type 0 = only initial, - ! 1 = emission rate in 1/s, - ! 2 = emission rate 1/iteration - REAL :: ParticleNumber ! Initial, Emission in [1/s] or [1/Iteration] - INTEGER(KIND=8) :: InsertedParticle ! Number of all already inserted Particles - INTEGER(KIND=8) :: InsertedParticleSurplus ! accumulated "negative" number of inserted Particles - INTEGER(KIND=4) :: InsertedParticleMisMatch=0 ! error in number of inserted particles of last step - INTEGER :: NumberOfExcludeRegions ! Number of different regions to be excluded - TYPE(tExcludeRegion), ALLOCATABLE :: ExcludeRegion(:) + CHARACTER(40) :: SpaceIC ! specifying Keyword for Particle Space condition + CHARACTER(30) :: velocityDistribution ! specifying keyword for velocity distribution + REAL :: Area ! Area for IC Rectangle + REAL :: RadiusIC ! Radius for IC circle + REAL :: Radius2IC ! Radius2 for IC cylinder (ring) + REAL :: RadiusICGyro ! Radius for Gyrotron gyro radius + REAL :: InflowRiseTime ! time to ramp the number of inflow particles + ! linearly from zero to unity + REAL :: NormalIC(3) ! Normal / Orientation of circle + REAL :: BasePointIC(3) ! base point for IC cuboid and IC sphere + REAL :: BaseVector1IC(3) ! first base vector for IC cuboid + REAL :: NormalVector1IC(3) ! 1st base vector normalized + REAL :: BaseVector2IC(3) ! second base vector for IC cuboid + REAL :: NormalVector2IC(3) ! 2nd base vector normalized + REAL :: CuboidHeightIC ! third measure of cuboid + ! (set 0 for flat rectangle), + ! negative value = opposite direction + REAL :: CylinderHeightIC ! third measure of cylinder + ! (set 0 for flat rectangle), + ! negative value = opposite direction + REAL :: VeloIC ! velocity for inital Data + REAL :: VeloVecIC(3) ! normalized velocity vector + REAL :: Amplitude ! Amplitude for sin-deviation initiation. + REAL :: WaveNumber ! WaveNumber for sin-deviation initiation. + INTEGER :: maxParticleNumberX ! Maximum Number of all Particles in x direction + INTEGER :: maxParticleNumberY ! Maximum Number of all Particles in y direction + INTEGER :: maxParticleNumberZ ! Maximum Number of all Particles in z direction + REAL :: Alpha ! WaveNumber for sin-deviation initiation. + REAL :: MWTemperatureIC ! Temperature for Maxwell Distribution + REAL :: PartDensity ! PartDensity (real particles per m^3) + INTEGER :: ParticleEmissionType ! Emission Type 0 = only initial, + ! 1 = emission rate in 1/s, + ! 2 = emission rate 1/iteration + REAL :: ParticleNumber ! Initial, Emission in [1/s] or [1/Iteration] + INTEGER(KIND=8) :: InsertedParticle ! Number of all already inserted Particles + INTEGER(KIND=8) :: InsertedParticleSurplus ! accumulated "negative" number of inserted Particles + INTEGER(KIND=4) :: InsertedParticleMisMatch=0 ! error in number of inserted particles of last step + INTEGER :: NumberOfExcludeRegions ! Number of different regions to be excluded + TYPE(tExcludeRegion), ALLOCATABLE :: ExcludeRegion(:) #if USE_MPI - INTEGER :: InitComm ! number of init-communicator + INTEGER :: InitComm ! number of init-communicator #endif /*USE_MPI*/ - INTEGER :: PartBCIndex ! Associated particle boundary ID - REAL :: MacroParticleFactor ! Emission-specific MPF -!====================================photo ionization ======================================================= + INTEGER :: PartBCIndex ! Associated particle boundary ID + REAL :: MacroParticleFactor ! Emission-specific MPF +!=== photo ionization LOGICAL :: FirstQuadrantOnly ! Only insert particles in the first quadrant that is spanned by the ! vectors x=BaseVector1IC and y=BaseVector2IC in the interval x,y in [0,R] REAL :: PulseDuration ! Pulse duration tau for a Gaussian-type pulse with @@ -117,6 +117,8 @@ MODULE MOD_Particle_Emission_Vars INTEGER :: mySumOfMatchedParticles ! Sum of matched particles on current proc !=== Background gas regions INTEGER :: BGGRegion ! Region number to be used for the species init +!=== Emission distribution + CHARACTER(30) :: EmissionDistributionName ! Species name, e.g., "electron" or "ArIon1" for particle emission END TYPE tInit ! 2D Landmark @@ -124,7 +126,6 @@ MODULE MOD_Particle_Emission_Vars ! ! Electrons and ions at the exact same position INTEGER :: NbrOfParticleLandmarkMax ! Array maximum size for storing positions INTEGER :: FractNbrOld,chunkSizeOld ! Auxiliary integers for storing positions - LOGICAL :: UseNeutralization ! Flag for counting the charged particles impinging on a surface CHARACTER(255) :: NeutralizationSource ! Name of the boundary for calculating the particle balance INTEGER :: nNeutralizationElems ! Number of elements used for neutralization source (if required) @@ -139,5 +140,17 @@ MODULE MOD_Particle_Emission_Vars ! to eV for usage in the code OR for neutralization BC (e.g. landmark) LOGICAL :: CalcBulkElectronTemp ! Automatic bulk electron calculation INTEGER :: BulkElectronTempSpecID ! Species ID (electron) for Automatic bulk electron calculation +! Emission distribution +LOGICAL :: UseEmissionDistribution !< Flag for activation particle emission by interpolation n, T and v (equidistant) +REAL,ALLOCATABLE :: EmissionDistribution(:,:) !< pos (r,z or x,y,z) and particle properties (n, T, vx, vy, vz) +CHARACTER(255) :: FileNameEmissionDistribution !< File name form which the data is read +INTEGER :: EmissionDistributionDim !< Spatial dimension of variable external field data: 1D, 2D or 3D +LOGICAL :: EmissionDistributionAxisSym !< True if the data is axis symmetric, e.g., B(r,z) +INTEGER :: EmissionDistributionRadInd !< Index of radial r-coordinate when using 2D data and axis symmetric +INTEGER :: EmissionDistributionAxisDir !< Direction that is used for the axial symmetric direction (1,2 or 3) +INTEGER :: EmissionDistributionN(1:3) !< Number of points in x, y and z-direction +REAL :: EmissionDistributionMin(1:3) !< Minimum values in x,y,z +REAL :: EmissionDistributionMax(1:3) !< Maximum values in x,y,z +REAL :: EmissionDistributionDelta(1:3) !< equidistant z-spacing for the VariableExternalField (fast computation) !=================================================================================================================================== END MODULE MOD_Particle_Emission_Vars diff --git a/src/particles/particle_mpi/particle_mpi_emission.f90 b/src/particles/particle_mpi/particle_mpi_emission.f90 index 01dbe97ae..94c7e5b00 100644 --- a/src/particles/particle_mpi/particle_mpi_emission.f90 +++ b/src/particles/particle_mpi/particle_mpi_emission.f90 @@ -493,6 +493,8 @@ SUBROUTINE InitEmissionComm() RegionOnProc=.TRUE. CASE ('background') RegionOnProc=.TRUE. + CASE ('EmissionDistribution') + RegionOnProc=.TRUE. CASE DEFAULT IPWRITE(*,*) 'ERROR: Species ', iSpec, 'of', iInit, 'is using an unknown SpaceIC!' CALL ABORT(__STAMP__,'ERROR: Given SpaceIC is not implemented: '//TRIM(Species(iSpec)%Init(iInit)%SpaceIC)) diff --git a/src/particles/pic/interpolation/pic_interpolation.f90 b/src/particles/pic/interpolation/pic_interpolation.f90 index 21e652921..9328b784b 100644 --- a/src/particles/pic/interpolation/pic_interpolation.f90 +++ b/src/particles/pic/interpolation/pic_interpolation.f90 @@ -86,7 +86,7 @@ SUBROUTINE DefineParametersPICInterpolation() CALL prms%CreateRealOption( 'PIC-scaleexternalField' , 'Scaling factor for PIC-externalField', '1.0') ! -- external field 3 -CALL prms%CreateStringOption( 'PIC-variableExternalField' , 'Method 3 of 5: CSV file containing the external magnetic field Bz in z-direction '//& +CALL prms%CreateStringOption( 'PIC-variableExternalField' , 'Method 3 of 5: H5 or CSV file containing the external magnetic field Bz in z-direction '//& 'for interpolating the variable field at each particle z-position.', 'none') ! -- external field 4 @@ -364,9 +364,11 @@ SUBROUTINE ReadVariableExternalField() !=================================================================================================================================== ! MODULES USE MOD_Globals -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalField,FileNameVariableExternalField -USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldDim,VariableExternalFieldAxisSym -USE MOD_HDF5_Input_Field ,ONLY: ReadVariableExternalFieldFromHDF5 +USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalField,FileNameVariableExternalField,DeltaExternalField,VariableExternalFieldDim +USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldDim,VariableExternalFieldAxisSym,VariableExternalFieldMin +USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldMax,VariableExternalFieldN,VariableExternalFieldAxisDir +USE MOD_PICInterpolation_Vars ,ONLY: VariableExternalFieldRadInd +USE MOD_HDF5_Input_Field ,ONLY: ReadExternalFieldFromHDF5 #if USE_LOADBALANCE USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance #endif /*USE_LOADBALANCE*/ @@ -383,10 +385,6 @@ SUBROUTINE ReadVariableExternalField() !=================================================================================================================================== LBWRITE(UNIT_stdOut,'(A,3X,A,65X,A)') ' INITIALIZATION OF VARIABLE EXTERNAL FIELD FOR PARTICLES ' -! Defaults -VariableExternalFieldDim = 1 ! default is 1D -VariableExternalFieldAxisSym = .FALSE. - ! Check if file exists IF(.NOT.FILEEXISTS(FileNameVariableExternalField)) CALL abort(__STAMP__,"File not found: "//TRIM(FileNameVariableExternalField)) @@ -396,7 +394,10 @@ SUBROUTINE ReadVariableExternalField() ! Check file ending, either .csv or .h5 IF(TRIM(FileNameVariableExternalField(lenstr-lenmin+2:lenstr)).EQ.'.h5')THEN - CALL ReadVariableExternalFieldFromHDF5() + CALL ReadExternalFieldFromHDF5('data',& + VariableExternalField , DeltaExternalField , FileNameVariableExternalField , VariableExternalFieldDim , & + VariableExternalFieldAxisSym , VariableExternalFieldRadInd , VariableExternalFieldAxisDir , VariableExternalFieldMin , & + VariableExternalFieldMax , VariableExternalFieldN) ELSEIF(TRIM(FileNameVariableExternalField(lenstr-lenmin+1:lenstr)).EQ.'.csv')THEN CALL ReadVariableExternalFieldFromCSV() ELSE diff --git a/src/particles/pic/interpolation/pic_interpolation_vars.f90 b/src/particles/pic/interpolation/pic_interpolation_vars.f90 index a7c139a88..66ccad1fc 100644 --- a/src/particles/pic/interpolation/pic_interpolation_vars.f90 +++ b/src/particles/pic/interpolation/pic_interpolation_vars.f90 @@ -33,7 +33,7 @@ MODULE MOD_PICInterpolation_Vars LOGICAL :: CalcBField !< Calculate the background field BGField from parameters defined in the !< input file -CHARACTER(LEN=256) :: FileNameVariableExternalField !< Filename containing the external field csv table +CHARACTER(LEN=255) :: FileNameVariableExternalField !< Filename containing the external field csv table LOGICAL :: useVariableExternalField !< Use given external field. Only for Bz variation in z LOGICAL :: useAlgebraicExternalField !< Use given algebraic expression for the external e and B field INTEGER :: AlgebraicExternalField !< External E and B field from algebraic expression that is From 4af3845d4ee1a858a2b3eabc7aa3c66c9e0ba960 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 15:24:02 +0200 Subject: [PATCH 02/36] Check for NaN when reading data in ReadExternalFieldFromHDF5() and nullify to prevent subsequent problems. --- src/io_hdf5/hdf5_input_field.f90 | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/io_hdf5/hdf5_input_field.f90 b/src/io_hdf5/hdf5_input_field.f90 index bbd210d1c..352de31ab 100644 --- a/src/io_hdf5/hdf5_input_field.f90 +++ b/src/io_hdf5/hdf5_input_field.f90 @@ -45,6 +45,9 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField ! use module !USE MOD_IO_HDF5 USE MOD_Globals +#if USE_MPI +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_MPI*/ !USE MOD_HDF5_Input ,ONLY: DatasetExists,ReadAttribute ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE @@ -71,8 +74,8 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField INTEGER(HSIZE_T), DIMENSION(2) :: dims,sizeMax INTEGER(HID_T) :: file_id_loc ! File identifier INTEGER(HID_T) :: dset_id_loc ! Dataset identifier -INTEGER(HID_T) :: filespace ! filespace identifier -LOGICAL :: DatasetFound,AttribtueFound +INTEGER(HID_T) :: filespace ! filespace identifier +LOGICAL :: DatasetFound,AttribtueFound,NaNDetected REAL :: delta,deltaOld INTEGER :: iDirMax !=================================================================================================================================== @@ -100,7 +103,6 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField ! Flip columns and rows between .h5 data and Fortran data NbrOfColumns = INT(dims(2)) ! this is the total number of points NbrOfRows = INT(dims(1)) ! this is the number of properties x,y,z,Bx,By,Bz - WRITE (*,*) "NbrOfColumns,NbrOfRows =", NbrOfColumns,NbrOfRows ! Read-in the data ALLOCATE(ExternalField(1:NbrOfRows,1:NbrOfColumns)) ExternalField=0. @@ -162,7 +164,16 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField END IF ! ExternalFieldDim.EQ.2 ! Loop x, y and z-coordinate and check deltas between points +NaNDetected=.FALSE. DO iDir = 1, iDirMax + ! Check for NaNs and nullify all properties except the coordinates of a data point + DO j = 1, NbrOfColumns + IF(ANY(ISNAN(ExternalField(ExternalFieldDim+1:NbrOfRows,j))))THEN + NaNDetected=.TRUE. + ExternalField(ExternalFieldDim+1:NbrOfRows,j) = 0. + END IF ! ANY(ISNAN(ExternalField(ExternalFieldDim+1:NbrOfRows,j))) + END DO + ! Get global min/max ExternalFieldMin(iDir) = MINVAL(ExternalField(iDir,:)) ExternalFieldMax(iDir) = MAXVAL(ExternalField(iDir,:)) @@ -200,6 +211,10 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField END DO ! j = 1, NbrOfColumns END DO ! iDir = 1, iDirMax +IF(NaNDetected) THEN + LBWRITE(UNIT_stdOut,'(A)') " Detected NaNs in "//TRIM(DataSet)//" dataset ("//TRIM(FileNameExternalField)//") replaced by 0.0" +END IF + ! Sanity check ASSOCIATE( x => ExternalFieldN(1:3) ) IF(ExternalFieldDim.EQ.2)THEN @@ -207,11 +222,11 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField ! z-dir: x(1) ! r-dir: x(2) IF(NbrOfColumns.NE.x(1)*x(2)) CALL abort(__STAMP__,'Wrong number of points in 2D') - SWRITE (UNIT_stdOut,'(A,2(I0,A))') " Read external field with ",x(1)," x ",x(2)," data points" + LBWRITE (UNIT_stdOut,'(A,2(I0,A))') " Read external field with ",x(1)," x ",x(2)," data points" ELSE IF(MINVAL(DeltaExternalField).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for external field.') IF(NbrOfColumns.NE.x(1)*x(2)*x(3)) CALL abort(__STAMP__,'Wrong number of points in 3D') - SWRITE (UNIT_stdOut,'(A,3(I0,A))') " Read external field with ",x(1)," x ",x(2)," x ",x(3)," data points" + LBWRITE (UNIT_stdOut,'(A,3(I0,A))') " Read external field with ",x(1)," x ",x(2)," x ",x(3)," data points" END IF ! ExternalFieldDim.EQ.2 END ASSOCIATE From 3f1b804bb1d766b51b2758a9897c8fedf85ba667 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 15:26:36 +0200 Subject: [PATCH 03/36] Small clean-up --- .../emission/particle_br_electron_fluid.f90 | 44 ++++----- .../emission/particle_emission_tools.f90 | 11 +-- .../particle_position_and_velocity.f90 | 94 +++++++++---------- src/particles/restart/particle_restart.f90 | 3 +- 4 files changed, 67 insertions(+), 85 deletions(-) diff --git a/src/particles/emission/particle_br_electron_fluid.f90 b/src/particles/emission/particle_br_electron_fluid.f90 index 1030d2139..805f6d60c 100644 --- a/src/particles/emission/particle_br_electron_fluid.f90 +++ b/src/particles/emission/particle_br_electron_fluid.f90 @@ -48,25 +48,18 @@ SUBROUTINE DefineParametersBR() !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES !=================================================================================================================================== -CALL prms%CreateIntOption( 'BRNbrOfRegions' , 'Number of regions to be mapped to Elements', '0') - -CALL prms%CreateStringOption( 'BRVariableElectronTemp', 'Variable electron reference temperature when using Boltzmann relation'//& - ' electron model (default is using a constant temperature)','constant') -CALL prms%CreateRealArrayOption('BRRegionBounds[$]' , 'BRRegionBounds ((xmin,xmax,ymin,...)|1:BRNbrOfRegions)'& - , '0. , 0. , 0. , 0. , 0. , 0.', numberedmulti=.TRUE.) -CALL prms%CreateRealArrayOption('Part-RegionElectronRef[$]' , 'rho_ref, phi_ref, and Te[eV] for Region#'& - , '0. , 0. , 1.', numberedmulti=.TRUE.) -CALL prms%CreateRealOption( 'Part-RegionElectronRef[$]-PhiMax' , 'max. expected phi for Region#\n'//& - '(linear approx. above! def.: phi_ref)', numberedmulti=.TRUE.) -CALL prms%CreateLogicalOption( 'BRConvertElectronsToFluid' , 'Remove all electrons when using BR electron fluid', '.FALSE.') -CALL prms%CreateLogicalOption( 'BRConvertFluidToElectrons' , 'Create electrons from BR electron fluid (requires'//& - ' ElectronDensityCell ElectronTemperatureCell from .h5 state file)'& - , '.FALSE.') -CALL prms%CreateRealOption( 'BRConvertFluidToElectronsTime', "Time when BR fluid electrons are to be converted to kinetic particles", '-1.0') -CALL prms%CreateRealOption( 'BRConvertElectronsToFluidTime', "Time when kinetic electrons should be converted to BR fluid electrons", '-1.0') -CALL prms%CreateLogicalOption( 'BRConvertModelRepeatedly' , 'Repeat the switch between BR and kinetic multiple times', '.FALSE.') -CALL prms%CreateRealOption( 'BRTimeStepMultiplier' , "Factor that is multiplied with the ManualTimeStep when using BR model", '1.0') -CALL prms%CreateLogicalOption( 'BRAutomaticElectronRef' , 'Automatically obtain the reference parameters (from a fully kinetic simulation)', '.FALSE.') +CALL prms%CreateIntOption( 'BRNbrOfRegions' , 'Number of regions to be mapped to Elements', '0') +CALL prms%CreateStringOption( 'BRVariableElectronTemp' , 'Variable electron reference temperature when using Boltzmann relation electron model (default is using a constant temperature)','constant') +CALL prms%CreateRealArrayOption('BRRegionBounds[$]' , 'BRRegionBounds ((xmin,xmax,ymin,...)|1:BRNbrOfRegions)', '0. , 0. , 0. , 0. , 0. , 0.', numberedmulti=.TRUE.) +CALL prms%CreateRealArrayOption('Part-RegionElectronRef[$]' , 'rho_ref, phi_ref, and Te[eV] for Region#', '0. , 0. , 1.', numberedmulti=.TRUE.) +CALL prms%CreateRealOption( 'Part-RegionElectronRef[$]-PhiMax' , 'max. expected phi for Region#\n (linear approx. above! def.: phi_ref)', numberedmulti=.TRUE.) +CALL prms%CreateLogicalOption( 'BRConvertElectronsToFluid' , 'Remove all electrons when using BR electron fluid', '.FALSE.') +CALL prms%CreateLogicalOption( 'BRConvertFluidToElectrons' , 'Create electrons from BR electron fluid (requires ElectronDensityCell ElectronTemperatureCell from .h5 state file)', '.FALSE.') +CALL prms%CreateRealOption( 'BRConvertFluidToElectronsTime' , "Time when BR fluid electrons are to be converted to kinetic particles", '-1.0') +CALL prms%CreateRealOption( 'BRConvertElectronsToFluidTime' , "Time when kinetic electrons should be converted to BR fluid electrons", '-1.0') +CALL prms%CreateLogicalOption( 'BRConvertModelRepeatedly' , 'Repeat the switch between BR and kinetic multiple times', '.FALSE.') +CALL prms%CreateRealOption( 'BRTimeStepMultiplier' , "Factor that is multiplied with the ManualTimeStep when using BR model", '1.0') +CALL prms%CreateLogicalOption( 'BRAutomaticElectronRef' , 'Automatically obtain the reference parameters (from a fully kinetic simulation)', '.FALSE.') END SUBROUTINE DefineParametersBR @@ -1001,9 +994,7 @@ SUBROUTINE CreateElectronsFromBRFluid(CreateFromRestartFile) EXIT END IF END DO -IF (ElecSpecIndx.LE.0) CALL abort(& - __STAMP__& - ,'Electron species not found. Cannot create electrons without the defined species!') +IF (ElecSpecIndx.LE.0) CALL abort(__STAMP__,'Electron species not found. Cannot create electrons without the defined species!') WRITE(UNIT=hilf,FMT='(I0)') iSpec SWRITE(UNIT_stdOut,'(A)')' Using iSpec='//TRIM(hilf)//' as electron species index from BR fluid conversion.' @@ -1034,14 +1025,12 @@ SUBROUTINE CreateElectronsFromBRFluid(CreateFromRestartFile) PDM%CurrentNextFreePosition = PDM%CurrentNextFreePosition + 1 ParticleIndexNbr = PDM%nextFreePosition(PDM%CurrentNextFreePosition) IF (ParticleIndexNbr.EQ.0) THEN - CALL Abort(& - __STAMP__& - ,'ERROR in CreateElectronsFromBRFluid(): New Particle Number greater max Part Num!') + CALL abort(__STAMP__,'ERROR in CreateElectronsFromBRFluid(): New Particle Number greater max Part Num!') END IF PDM%ParticleVecLength = PDM%ParticleVecLength + 1 !Set new SpeciesID of new particle (electron) - PDM%ParticleInside(ParticleIndexNbr) = .true. + PDM%ParticleInside(ParticleIndexNbr) = .TRUE. PartSpecies(ParticleIndexNbr) = ElecSpecIndx ! Place the electron randomly in the reference cell @@ -1060,7 +1049,8 @@ SUBROUTINE CreateElectronsFromBRFluid(CreateFromRestartFile) END IF ! Set the element ID of the electron to the current element ID - PEM%GlobalElemID(ParticleIndexNbr) = iElem + offsetElem + PEM%GlobalElemID(ParticleIndexNbr) = iElem + offsetElem + PEM%LastGlobalElemID(ParticleIndexNbr) = PEM%GlobalElemID(ParticleIndexNbr) ! Set the electron velocity using the Maxwellian distribution (use the function that is suitable for small numbers) IF(CreateFromRestartFile)THEN diff --git a/src/particles/emission/particle_emission_tools.f90 b/src/particles/emission/particle_emission_tools.f90 index a373e0855..37e24470f 100644 --- a/src/particles/emission/particle_emission_tools.f90 +++ b/src/particles/emission/particle_emission_tools.f90 @@ -262,9 +262,7 @@ SUBROUTINE SetParticleChargeAndMass(FractNbr,NbrOfParticle) IF (PositionNbr .NE. 0) THEN PartSpecies(PositionNbr) = FractNbr ELSE - CALL abort(& - __STAMP__& - ,'ERROR in SetParticlePosition:ParticleIndexNbr.EQ.0 - maximum nbr of particles reached?') + CALL abort(__STAMP__,'ERROR in SetParticlePosition:ParticleIndexNbr.EQ.0 - maximum nbr of particles reached?') END IF END DO @@ -952,9 +950,7 @@ SUBROUTINE SetCellLocalParticlePosition(chunkSize,iSpec,iInit,UseExactPartNum) !----------------------------------------------------------------------------------------------------------------------------------- IF (UseExactPartNum) THEN IF(chunkSize.GE.PDM%maxParticleNumber) THEN - CALL abort(& -__STAMP__,& -'ERROR in SetCellLocalParticlePosition: Maximum particle number reached! max. particles needed: ',chunksize) + CALL abort(__STAMP__,'SetCellLocalParticlePosition: Maximum particle number reached! max. particles needed: ',chunksize) END IF CellChunkSize(:)=0 ASSOCIATE( start => GetCNElemID(1+offsetElem),& @@ -1027,8 +1023,7 @@ SUBROUTINE SetCellLocalParticlePosition(chunkSize,iSpec,iInit,UseExactPartNum) IPWRITE(UNIT_stdOut,*) "ERROR:" IPWRITE(UNIT_stdOut,*) " iPart :", iPart IPWRITE(UNIT_stdOut,*) "PDM%maxParticleNumber :", PDM%maxParticleNumber - CALL abort(& - __STAMP__& + CALL abort(__STAMP__& ,'ERROR in SetCellLocalParticlePosition: Maximum particle number reached during inserting! --> ParticleIndexNbr.EQ.0') END IF END DO diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index 9001f746a..ea6ce0c7a 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -41,7 +41,7 @@ MODULE MOD_part_pos_and_velo SUBROUTINE SetParticlePositionCellLocal(FractNbr,iInit,NbrOfParticle) !=================================================================================================================================== -! Set particle position +! Set particle position for processor-local particles (only in processor elements) !=================================================================================================================================== ! modules USE MOD_Globals @@ -71,57 +71,55 @@ SUBROUTINE SetParticlePositionCellLocal(FractNbr,iInit,NbrOfParticle) #endif !===================================================================================================================================/ - DoExactPartNumInsert = .FALSE. - ! check if particle inserting during simulation or initial inserting and also if via partdensity or exact particle number - ! nbrOfParticles is set for initial inserting if initialPartNum or partdensity is set in ini - ! ParticleNumber and PartDensity not working together - IF (NbrofParticle.EQ.0.AND.(Species(FractNbr)%Init(iInit)%ParticleNumber.EQ.0)) RETURN - IF ((NbrofParticle.GT.0).AND.(Species(FractNbr)%Init(iInit)%PartDensity.LE.0.)) THEN - DoExactPartNumInsert = .TRUE. - IF(Symmetry%Axisymmetric) CALL abort(& -__STAMP__& -,'Axisymmetric: Particle insertion only possible with PartDensity!') - END IF - chunksize = 0 +DoExactPartNumInsert = .FALSE. +! check if particle inserting during simulation or initial inserting and also if via partdensity or exact particle number +! nbrOfParticles is set for initial inserting if initialPartNum or partdensity is set in ini +! ParticleNumber and PartDensity not working together +IF (NbrofParticle.EQ.0.AND.(Species(FractNbr)%Init(iInit)%ParticleNumber.EQ.0)) RETURN +IF ((NbrofParticle.GT.0).AND.(Species(FractNbr)%Init(iInit)%PartDensity.LE.0.)) THEN + DoExactPartNumInsert = .TRUE. + IF(Symmetry%Axisymmetric) CALL abort(__STAMP__,'Axisymmetric: Particle insertion only possible with PartDensity!') +END IF +chunksize = 0 #if USE_MPI ! emission group communicator - InitGroup=Species(FractNbr)%Init(iInit)%InitCOMM - IF(PartMPI%InitGroup(InitGroup)%COMM.EQ.MPI_COMM_NULL) THEN - NbrofParticle=0 - RETURN - END IF - IF (PartMPI%InitGroup(InitGroup)%nProcs.GT.1) THEN - IF (DoExactPartNumInsert) THEN !###$ ToDo - IF (PartMPI%InitGroup(InitGroup)%MPIROOT) THEN - ALLOCATE(ProcMeshVol(0:PartMPI%InitGroup(InitGroup)%nProcs-1)) - ALLOCATE(ProcNbrOfParticle(0:PartMPI%InitGroup(InitGroup)%nProcs-1)) - ProcMeshVol=0. - ProcNbrOfParticle=0 - ELSE ! to reduce global memory allocation if a lot of procs are used - ALLOCATE(ProcMeshVol(1)) - ALLOCATE(ProcNbrOfParticle(1)) - ProcMeshVol=0. - ProcNbrOfParticle=0 - END IF !InitGroup%MPIroot - CALL MPI_GATHER(LocalVolume,1,MPI_DOUBLE_PRECISION & - ,ProcMeshVol,1,MPI_DOUBLE_PRECISION,0,PartMPI%InitGroup(InitGroup)%COMM,iError) - IF (PartMPI%InitGroup(InitGroup)%MPIROOT) THEN - CALL IntegerDivide(NbrOfParticle,PartMPI%InitGroup(InitGroup)%nProcs,ProcMeshVol,ProcNbrOfParticle) - END IF - CALL MPI_SCATTER(ProcNbrOfParticle, 1, MPI_INTEGER, chunksize, 1, MPI_INTEGER, 0, PartMPI%InitGroup(InitGroup)%COMM, IERROR) - SDEALLOCATE(ProcMeshVol) - SDEALLOCATE(ProcNbrOfParticle) +InitGroup=Species(FractNbr)%Init(iInit)%InitCOMM +IF(PartMPI%InitGroup(InitGroup)%COMM.EQ.MPI_COMM_NULL) THEN + NbrofParticle=0 + RETURN +END IF +IF (PartMPI%InitGroup(InitGroup)%nProcs.GT.1) THEN + IF (DoExactPartNumInsert) THEN !###$ ToDo + IF (PartMPI%InitGroup(InitGroup)%MPIROOT) THEN + ALLOCATE(ProcMeshVol(0:PartMPI%InitGroup(InitGroup)%nProcs-1)) + ALLOCATE(ProcNbrOfParticle(0:PartMPI%InitGroup(InitGroup)%nProcs-1)) + ProcMeshVol=0. + ProcNbrOfParticle=0 + ELSE ! to reduce global memory allocation if a lot of procs are used + ALLOCATE(ProcMeshVol(1)) + ALLOCATE(ProcNbrOfParticle(1)) + ProcMeshVol=0. + ProcNbrOfParticle=0 + END IF !InitGroup%MPIroot + CALL MPI_GATHER(LocalVolume,1,MPI_DOUBLE_PRECISION & + ,ProcMeshVol,1,MPI_DOUBLE_PRECISION,0,PartMPI%InitGroup(InitGroup)%COMM,iError) + IF (PartMPI%InitGroup(InitGroup)%MPIROOT) THEN + CALL IntegerDivide(NbrOfParticle,PartMPI%InitGroup(InitGroup)%nProcs,ProcMeshVol,ProcNbrOfParticle) END IF - ELSE - chunksize = NbrOfParticle + CALL MPI_SCATTER(ProcNbrOfParticle, 1, MPI_INTEGER, chunksize, 1, MPI_INTEGER, 0, PartMPI%InitGroup(InitGroup)%COMM, IERROR) + SDEALLOCATE(ProcMeshVol) + SDEALLOCATE(ProcNbrOfParticle) END IF +ELSE + chunksize = NbrOfParticle +END IF #else - IF (DoExactPartNumInsert) chunksize = NbrOfParticle +IF (DoExactPartNumInsert) chunksize = NbrOfParticle #endif /*USE_MPI*/ - IF ((chunksize.GT.0).OR.(Species(FractNbr)%Init(iInit)%PartDensity.GT.0.)) THEN - CALL SetCellLocalParticlePosition(chunkSize,FractNbr,iInit,DoExactPartNumInsert) - END IF - NbrOfParticle = chunksize +IF ((chunksize.GT.0).OR.(Species(FractNbr)%Init(iInit)%PartDensity.GT.0.)) THEN + CALL SetCellLocalParticlePosition(chunkSize,FractNbr,iInit,DoExactPartNumInsert) +END IF +NbrOfParticle = chunksize END SUBROUTINE SetParticlePositionCellLocal @@ -174,8 +172,8 @@ SUBROUTINE SetParticlePosition(FractNbr,iInit,NbrOfParticle) Species(FractNbr)%Init(iInit)%sumOfRequestedParticles = NbrOfParticle IF((NbrOfParticle.LE.0).AND.(ABS(Species(FractNbr)%Init(iInit)%PartDensity).LE.0.)) RETURN -DimSend = 3 !save (and send) only positions -nChunks = 1 ! Standard: Nicht-MPI +DimSend = 3 ! save (and send) only positions +nChunks = 1 ! Standard: Nicht-MPI Species(FractNbr)%Init(iInit)%sumOfMatchedParticles = 0 Species(FractNbr)%Init(iInit)%mySumOfMatchedParticles = 0 chunkSize = nbrOfParticle diff --git a/src/particles/restart/particle_restart.f90 b/src/particles/restart/particle_restart.f90 index 173727cea..5178f875e 100644 --- a/src/particles/restart/particle_restart.f90 +++ b/src/particles/restart/particle_restart.f90 @@ -1116,8 +1116,7 @@ SUBROUTINE MacroscopicRestart() CALL ReadAttribute(File_ID,'File_Type',1,StrScalar=File_Type) IF(TRIM(File_Type).NE.'DSMCState') THEN SWRITE(*,*) 'ERROR: The given file type is: ', TRIM(File_Type) - CALL abort(__STAMP__,& - 'ERROR: Given file for the macroscopic restart is not of the type "DSMCState", please check the input file!') + CALL abort(__STAMP__,'ERROR: Given file for the macroscopic restart is not of the type "DSMCState", please check the input file!') END IF CALL GetDataSize(File_ID,'ElemData',nDims,HSize,attrib=.FALSE.) From c10abf0f9e15909da491cff7358ca670f90767f1 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 17:00:29 +0200 Subject: [PATCH 04/36] Renamed MacroRestart_InitializeParticle_Maxwell() to InitializeParticleMaxwell() and moved to particle_tools.f90 for more general use also in other particle emission models. --- .../emission/particle_macroscopic_restart.f90 | 87 ++-------------- src/particles/particle_tools.f90 | 99 +++++++++++++++++++ 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/src/particles/emission/particle_macroscopic_restart.f90 b/src/particles/emission/particle_macroscopic_restart.f90 index 79c4a3eaa..ad2a6f571 100644 --- a/src/particles/emission/particle_macroscopic_restart.f90 +++ b/src/particles/emission/particle_macroscopic_restart.f90 @@ -38,7 +38,7 @@ SUBROUTINE MacroRestart_InsertParticles() USE MOD_Globals USE MOD_Globals_Vars ,ONLY: Pi USE MOD_DSMC_Vars ,ONLY: RadialWeighting, DSMC -USE MOD_part_tools ,ONLY: CalcRadWeightMPF +USE MOD_part_tools ,ONLY: CalcRadWeightMPF,InitializeParticleMaxwell USE MOD_Mesh_Vars ,ONLY: nElems,offsetElem USE MOD_Particle_VarTimeStep ,ONLY: CalcVarTimeStep USE MOD_Particle_Vars ,ONLY: Species, PDM, nSpecies, PartState, Symmetry, VarTimeStep @@ -98,7 +98,7 @@ SUBROUTINE MacroRestart_InsertParticles() InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) IF (InsideFlag) THEN PartState(1:3,locnPart) = RandomPos(1:3) - CALL MacroRestart_InitializeParticle_Maxwell(locnPart,iSpec,iElem) + CALL InitializeParticleMaxwell(locnPart,iSpec,iElem,Mode=1) locnPart = locnPart + 1 END IF END DO ! nPart @@ -125,7 +125,7 @@ SUBROUTINE MacroRestart_InsertParticles() InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) END DO PartState(1:3,locnPart) = RandomPos(1:3) - CALL MacroRestart_InitializeParticle_Maxwell(locnPart,iSpec,iElem) + CALL InitializeParticleMaxwell(locnPart,iSpec,iElem,Mode=1) locnPart = locnPart + 1 END DO ! nPart END DO ! nSpecies @@ -150,7 +150,7 @@ SUBROUTINE MacroRestart_InsertParticles() InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) IF (InsideFlag) THEN PartState(1:3,locnPart) = RandomPos(1:3) - CALL MacroRestart_InitializeParticle_Maxwell(locnPart,iSpec,iElem) + CALL InitializeParticleMaxwell(locnPart,iSpec,iElem,Mode=1) locnPart = locnPart + 1 END IF END DO ! nPart @@ -176,7 +176,7 @@ SUBROUTINE MacroRestart_InsertParticles() InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) IF (InsideFlag) THEN PartState(1:3,locnPart) = RandomPos(1:3) - CALL MacroRestart_InitializeParticle_Maxwell(locnPart,iSpec,iElem) + CALL InitializeParticleMaxwell(locnPart,iSpec,iElem,Mode=1) locnPart = locnPart + 1 END IF END DO ! nPart @@ -201,7 +201,7 @@ SUBROUTINE MacroRestart_InsertParticles() InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) IF (InsideFlag) THEN PartState(1:3,locnPart) = RandomPos(1:3) - CALL MacroRestart_InitializeParticle_Maxwell(locnPart,iSpec,iElem) + CALL InitializeParticleMaxwell(locnPart,iSpec,iElem,Mode=1) locnPart = locnPart + 1 END IF END DO ! nPart @@ -210,84 +210,11 @@ SUBROUTINE MacroRestart_InsertParticles() END ASSOCIATE END DO ! nElems -IF(locnPart.GE.PDM%maxParticleNumber) THEN - CALL abort(__STAMP__,& - 'ERROR in MacroRestart: Increase maxParticleNumber!', locnPart) -END IF +IF(locnPart.GE.PDM%maxParticleNumber) CALL abort(__STAMP__,'ERROR in MacroRestart: Increase maxParticleNumber!', locnPart) PDM%ParticleVecLength = PDM%ParticleVecLength + locnPart END SUBROUTINE MacroRestart_InsertParticles -SUBROUTINE MacroRestart_InitializeParticle_Maxwell(iPart,iSpec,iElem) -!=================================================================================================================================== -!> Initialize a particle from a given macroscopic result, requires the macroscopic velocity, translational and internal temperatures -!=================================================================================================================================== -! MODULES -USE MOD_Globals -USE MOD_Mesh_Vars ,ONLY: offSetElem -USE MOD_Particle_Vars ,ONLY: PDM, PartSpecies, PartState, PEM, VarTimeStep, PartMPF, Species -USE MOD_DSMC_Vars ,ONLY: DSMC, PartStateIntEn, CollisMode, SpecDSMC, RadialWeighting, AmbipolElecVelo -USE MOD_Restart_Vars ,ONLY: MacroRestartValues -USE MOD_Particle_VarTimeStep ,ONLY: CalcVarTimeStep -USE MOD_part_tools ,ONLY: CalcRadWeightMPF, CalcEElec_particle, CalcEVib_particle, CalcERot_particle -USE MOD_part_tools ,ONLY: CalcVelocity_maxwell_particle -!----------------------------------------------------------------------------------------------------------------------------------- -! IMPLICIT VARIABLE HANDLING -IMPLICIT NONE -!----------------------------------------------------------------------------------------------------------------------------------- -! INPUT VARIABLES -INTEGER, INTENT(IN) :: iPart, iSpec, iElem -!----------------------------------------------------------------------------------------------------------------------------------- -! OUTPUT VARIABLES -!----------------------------------------------------------------------------------------------------------------------------------- -! LOCAL VARIABLES -!=================================================================================================================================== - -! 1) Set particle velocity from macroscopic bulk velocity and translational temperature in the cell -PartState(4:6,iPart) = CalcVelocity_maxwell_particle(iSpec,MacroRestartValues(iElem,iSpec,4:6)) & - + MacroRestartValues(iElem,iSpec,1:3) - -IF (DSMC%DoAmbipolarDiff) THEN - IF(Species(iSpec)%ChargeIC.GT.0.0) THEN - IF (ALLOCATED(AmbipolElecVelo(iPart)%ElecVelo)) DEALLOCATE(AmbipolElecVelo(iPart)%ElecVelo) - ALLOCATE(AmbipolElecVelo(iPart)%ElecVelo(3)) - AmbipolElecVelo(iPart)%ElecVelo(1:3) = CalcVelocity_maxwell_particle(DSMC%AmbiDiffElecSpec, & - MacroRestartValues(iElem,DSMC%AmbiDiffElecSpec,4:6)) + MacroRestartValues(iElem,DSMC%AmbiDiffElecSpec,1:3) - END IF -END IF -! 2) Set internal energies (rotational, vibrational, electronic) -IF(CollisMode.GT.1) THEN - IF((SpecDSMC(iSpec)%InterID.EQ.2).OR.(SpecDSMC(iSpec)%InterID.EQ.20)) THEN - PartStateIntEn(1,iPart) = CalcEVib_particle(iSpec,MacroRestartValues(iElem,iSpec,DSMC_TVIB),iPart) - PartStateIntEn(2,iPart) = CalcERot_particle(iSpec,MacroRestartValues(iElem,iSpec,DSMC_TROT)) - ELSE - PartStateIntEn(1:2,iPart) = 0.0 - END IF - IF(DSMC%ElectronicModel.GT.0) THEN - IF((SpecDSMC(iSpec)%InterID.NE.4).AND.(.NOT.SpecDSMC(iSpec)%FullyIonized)) THEN - PartStateIntEn(3,iPart) = CalcEElec_particle(iSpec,MacroRestartValues(iElem,iSpec,DSMC_TELEC),iPart) - ELSE - PartStateIntEn(3,iPart) = 0.0 - END IF - END IF -END IF - -! 3) Set the species and element number -PartSpecies(iPart) = iSpec -PEM%GlobalElemID(iPart) = iElem+offSetElem -PEM%LastGlobalElemID(iPart) = iElem+offSetElem -PDM%ParticleInside(iPart) = .TRUE. - -! 4) Set particle weights (if required) -IF (VarTimeStep%UseVariableTimeStep) THEN - VarTimeStep%ParticleTimeStep(iPart) = CalcVarTimeStep(PartState(1,iPart),PartState(2,iPart),iElem) -END IF -IF (RadialWeighting%DoRadialWeighting) THEN - PartMPF(iPart) = CalcRadWeightMPF(PartState(2,iPart),iSpec,iPart) -END IF - -END SUBROUTINE MacroRestart_InitializeParticle_Maxwell - END MODULE MOD_Macro_Restart diff --git a/src/particles/particle_tools.f90 b/src/particles/particle_tools.f90 index ee0712bce..451c15ccf 100644 --- a/src/particles/particle_tools.f90 +++ b/src/particles/particle_tools.f90 @@ -61,6 +61,7 @@ MODULE MOD_part_tools PUBLIC :: UpdateNextFreePosition, DiceUnitVector, VeloFromDistribution, GetParticleWeight, CalcRadWeightMPF, isChargedParticle PUBLIC :: isPushParticle, isDepositParticle, isInterpolateParticle, StoreLostParticleProperties, BuildTransGaussNums PUBLIC :: CalcXiElec,ParticleOnProc, CalcERot_particle, CalcEVib_particle, CalcEElec_particle, CalcVelocity_maxwell_particle +PUBLIC :: InitializeParticleMaxwell !=================================================================================================================================== CONTAINS @@ -985,4 +986,102 @@ REAL FUNCTION CalcEElec_particle(iSpec,TempElec,iPart) END FUNCTION CalcEElec_particle +SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) +!=================================================================================================================================== +!> Initialize a particle from a given macroscopic result, requires the macroscopic velocity, translational and internal temperatures +!=================================================================================================================================== +! MODULES +USE MOD_Globals +USE MOD_Mesh_Vars ,ONLY: offSetElem +USE MOD_Particle_Vars ,ONLY: PDM, PartSpecies, PartState, PEM, VarTimeStep, PartMPF, Species +USE MOD_DSMC_Vars ,ONLY: DSMC, PartStateIntEn, CollisMode, SpecDSMC, RadialWeighting, AmbipolElecVelo +USE MOD_Restart_Vars ,ONLY: MacroRestartValues +USE MOD_Particle_VarTimeStep ,ONLY: CalcVarTimeStep +!USE MOD_part_tools ,ONLY: CalcRadWeightMPF, CalcEElec_particle, CalcEVib_particle, CalcERot_particle +!USE MOD_part_tools ,ONLY: CalcVelocity_maxwell_particle +!----------------------------------------------------------------------------------------------------------------------------------- +! IMPLICIT VARIABLE HANDLING +IMPLICIT NONE +!----------------------------------------------------------------------------------------------------------------------------------- +! INPUT VARIABLES +INTEGER, INTENT(IN) :: iPart, iSpec, iElem +INTEGER, INTENT(IN) :: Mode !< 1: Macroscopic restart (data for each element) + !< 2: Emission distribution (equidistant data from .h5 file) +!----------------------------------------------------------------------------------------------------------------------------------- +! OUTPUT VARIABLES +!----------------------------------------------------------------------------------------------------------------------------------- +! LOCAL VARIABLES +CHARACTER(LEN=100) :: hilf !< auxiliary variable fr error output +INTEGER :: iSpecAD !< ambipolar diffusion species ID +REAL :: v(3),vAD(3) !< velocity vector (vAD corresponds to ambipolar diffusion) +REAL :: T(3),TAD(3) !< temperature vector (TAD corresponds to ambipolar diffusion) +REAL :: Tvib !< vibrational temperature +REAL :: Trot !< rotational temperature +REAL :: Telec !< electronic temperature +!=================================================================================================================================== + +SELECT CASE(Mode) +CASE(1) ! Macroscopic restart (data for each element) + v = MacroRestartValues(iElem,iSpec,1:3) + T = MacroRestartValues(iElem,iSpec,4:6) + iSpecAD = DSMC%AmbiDiffElecSpec + vAD = MacroRestartValues(iElem,iSpecAD,1:3) + TAD = MacroRestartValues(iElem,iSpecAD,4:6) + Tvib = MacroRestartValues(iElem,iSpec,DSMC_TVIB) + Trot = MacroRestartValues(iElem,iSpec,DSMC_TROT) + Telec = MacroRestartValues(iElem,iSpec,DSMC_TELEC) +CASE(2) ! Emission distribution (equidistant data from .h5 file) + ! Sanity check + hilf=' is not implemented in InitializeParticleMaxwell() in combination with EmissionDistribution yet!' + IF(DSMC%DoAmbipolarDiff) CALL abort(__STAMP__,'DSMC%DoAmbipolarDiff=T'//TRIM(hilf)) + IF(VarTimeStep%UseVariableTimeStep) CALL abort(__STAMP__,'VarTimeStep%UseVariableTimeStep=T'//TRIM(hilf)) + IF(RadialWeighting%DoRadialWeighting) CALL abort(__STAMP__,'RadialWeighting%DoRadialWeighting=T'//TRIM(hilf)) +CASE DEFAULT + CALL abort(__STAMP__,'InitializeParticleMaxwell: Mode option is unknown. Mode=',IntInfoOpt=Mode) +END SELECT + +! 1) Set particle velocity from macroscopic bulk velocity and translational temperature in the cell +PartState(4:6,iPart) = CalcVelocity_maxwell_particle(iSpec,T(1:3)) + v(1:3) + +IF (DSMC%DoAmbipolarDiff) THEN + IF(Species(iSpec)%ChargeIC.GT.0.0) THEN + IF (ALLOCATED(AmbipolElecVelo(iPart)%ElecVelo)) DEALLOCATE(AmbipolElecVelo(iPart)%ElecVelo) + ALLOCATE(AmbipolElecVelo(iPart)%ElecVelo(3)) + AmbipolElecVelo(iPart)%ElecVelo(1:3) = CalcVelocity_maxwell_particle(iSpecAD, TAD(1:3) ) + vAD(1:3) + END IF +END IF +! 2) Set internal energies (rotational, vibrational, electronic) +IF(CollisMode.GT.1) THEN + IF((SpecDSMC(iSpec)%InterID.EQ.2).OR.(SpecDSMC(iSpec)%InterID.EQ.20)) THEN + PartStateIntEn(1,iPart) = CalcEVib_particle(iSpec,Tvib,iPart) + PartStateIntEn(2,iPart) = CalcERot_particle(iSpec,Trot) + ELSE + PartStateIntEn(1:2,iPart) = 0.0 + END IF + IF(DSMC%ElectronicModel.GT.0) THEN + IF((SpecDSMC(iSpec)%InterID.NE.4).AND.(.NOT.SpecDSMC(iSpec)%FullyIonized)) THEN + PartStateIntEn(3,iPart) = CalcEElec_particle(iSpec,Telec,iPart) + ELSE + PartStateIntEn(3,iPart) = 0.0 + END IF + END IF +END IF + +! 3) Set the species and element number +PartSpecies(iPart) = iSpec +PEM%GlobalElemID(iPart) = iElem+offSetElem +PEM%LastGlobalElemID(iPart) = iElem+offSetElem +PDM%ParticleInside(iPart) = .TRUE. + +! 4) Set particle weights (if required) +IF (VarTimeStep%UseVariableTimeStep) THEN + VarTimeStep%ParticleTimeStep(iPart) = CalcVarTimeStep(PartState(1,iPart),PartState(2,iPart),iElem) +END IF +IF (RadialWeighting%DoRadialWeighting) THEN + PartMPF(iPart) = CalcRadWeightMPF(PartState(2,iPart),iSpec,iPart) +END IF + +END SUBROUTINE InitializeParticleMaxwell + + END MODULE MOD_part_tools From 4866b27c9c523e4b54959c3c2bf1ff1daecf4634 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 19:54:15 +0200 Subject: [PATCH 05/36] Particle emission via 'EmissionDistribution' now working for single species. --- .../parameter.ini | 6 +- ...reggie-linear-rot-symmetry-species-init.h5 | Bin 5984 -> 7216 bytes .../emission/particle_emission_init.f90 | 39 +++--- .../particle_position_and_velocity.f90 | 78 ++++++++++- src/particles/particle_tools.f90 | 121 ++++++++++++++++++ 5 files changed, 225 insertions(+), 19 deletions(-) diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini index ac38039c5..e31b07950 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini @@ -37,6 +37,8 @@ CalcMeshInfo=T CalcHaloInfo=T CalcEMFieldOutput=T !Particles-HaloEpsVelo=1e9 +CalcElectronIonDensity=T +CalcElectronTemperature=T ! =============================================================================== ! ! Load Balance @@ -73,7 +75,7 @@ Part-FileNameEmissionDistribution = reggie-linear-rot-symmetry-species-init.h5 ! =============================================================================== ! Part-Species1-ChargeIC = -1.60217653E-19 Part-Species1-MassIC = 9.1093826E-31 -Part-Species1-MacroParticleFactor = 1E6 +Part-Species1-MacroParticleFactor = 1E12 Part-Species1-nInits = 1 @@ -85,7 +87,7 @@ Part-Species1-Init1-EmissionDistributionName = electron ! =============================================================================== ! Part-Species2-ChargeIC = 1.60217653E-19 Part-Species2-MassIC = 6.645565470903E-027 -Part-Species2-MacroParticleFactor = 1E6 +Part-Species2-MacroParticleFactor = 1E12 Part-Species2-nInits = 1 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 index 0c068c39a9b41c7961bc3e9f7f054aed95c23d2c..aabf4ffd4d6a9eafff317c461edd35eed407f676 100644 GIT binary patch delta 1060 zcmaE$x4~k929trzL@f(O-igV+j2as^vNJI{Y~IQAoKcXC0RlvzG~48jERI|Xf)MTj z=E;9pB$!JN*-p;qF60dM^LJrnU}8v^JdstMO9QGUL45N?R#T>l2lyw;@p5eD%r(kcAdts^H^9Q6V6VVn%~7&?%g#PH7NEbqYvLADWsESk#Kk z88be(9yLyd$@h3UVS3v55cU9N&hf!ra19}|3{^&rAF4-a@;gq6$^S$YCfD&RK%6Ty zS&s`OG?}qtvKO=7dVeewq;3CYx))Z~(){5)t7GB83J J2@^Ml0{}r5Y;ynr diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index 21f05be16..3526403f4 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -420,8 +420,10 @@ SUBROUTINE InitializeVariablesSpeciesInits() END IF !--- Emission distribution IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN - UseEmissionDistribution = .TRUE. + UseEmissionDistribution = .TRUE. Species(iSpec)%Init(iInit)%EmissionDistributionName = TRIM(GETSTR('Part-Species'//TRIM(hilf2)//'-EmissionDistributionName')) + Species(iSpec)%Init(iInit)%ParticleEmissionType = 0 ! initial particle insert + Species(iSpec)%Init(iInit)%ParticleNumber = 0 ! force 0 END IF ! TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution' END DO ! iInit END DO ! iSpec @@ -464,7 +466,7 @@ SUBROUTINE InitialParticleInserting() USE MOD_Dielectric_Vars ,ONLY: DoDielectric,isDielectricElem,DielectricNoParticles USE MOD_DSMC_Vars ,ONLY: useDSMC, DSMC USE MOD_Part_Emission_Tools ,ONLY: SetParticleChargeAndMass,SetParticleMPF,SetParticleTimeStep -USE MOD_Part_Pos_and_Velo ,ONLY: SetParticlePosition,SetParticleVelocity +USE MOD_Part_Pos_and_Velo ,ONLY: SetParticlePosition,SetParticleVelocity,SetPartPosAndVeloEmissionDistribution USE MOD_DSMC_AmbipolarDiffusion ,ONLY: AD_SetInitElectronVelo USE MOD_Part_Tools ,ONLY: UpdateNextFreePosition USE MOD_Particle_Vars ,ONLY: Species,nSpecies,PDM,PEM, usevMPF, SpecReset, VarTimeStep @@ -497,12 +499,18 @@ SUBROUTINE InitialParticleInserting() DO iInit = 1, Species(iSpec)%NumberOfInits IF (Species(iSpec)%Init(iInit)%ParticleEmissionType.EQ.0) THEN IF(Species(iSpec)%Init(iInit)%ParticleNumber.GT.HUGE(1)) CALL abort(__STAMP__,& - ' Integer of initial particle number larger than max integer size: ',HUGE(1)) - NbrOfParticle = INT(Species(iSpec)%Init(iInit)%ParticleNumber,4) - LBWRITE(UNIT_stdOut,'(A,I0,A)') ' Set particle position for species ',iSpec,' ... ' - CALL SetParticlePosition(iSpec,iInit,NbrOfParticle) - LBWRITE(UNIT_stdOut,'(A,I0,A)') ' Set particle velocities for species ',iSpec,' ... ' - CALL SetParticleVelocity(iSpec,iInit,NbrOfParticle) + ' Integer of initial particle number larger than max integer size: ',IntInfoOpt=HUGE(1)) + ! Set particle position and velocity + SELECT CASE(TRIM(Species(iSpec)%Init(iInit)%SpaceIC)) + CASE('EmissionDistribution') + CALL SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) + CASE DEFAULT + NbrOfParticle = INT(Species(iSpec)%Init(iInit)%ParticleNumber,4) + LBWRITE(UNIT_stdOut,'(A,I0,A)') ' Set particle position for species ',iSpec,' ... ' + CALL SetParticlePosition(iSpec,iInit,NbrOfParticle) + LBWRITE(UNIT_stdOut,'(A,I0,A)') ' Set particle velocities for species ',iSpec,' ... ' + CALL SetParticleVelocity(iSpec,iInit,NbrOfParticle) + END SELECT LBWRITE(UNIT_stdOut,'(A,I0,A)') ' Set particle charge and mass for species ',iSpec,' ... ' CALL SetParticleChargeAndMass(iSpec,NbrOfParticle) IF (usevMPF) CALL SetParticleMPF(iSpec,iInit,NbrOfParticle) @@ -514,12 +522,13 @@ SUBROUTINE InitialParticleInserting() IF (PositionNbr .NE. 0) THEN PDM%PartInit(PositionNbr) = iInit ELSE - CALL abort(__STAMP__,& - 'ERROR in InitialParticleInserting: No free particle index - maximum nbr of particles reached?') + CALL abort(__STAMP__,'ERROR in InitialParticleInserting: No free particle index - maximum nbr of particles reached?') END IF END DO END IF + ! Add new particles to particle vector length PDM%ParticleVecLength = PDM%ParticleVecLength + NbrOfParticle + ! Update CALL UpdateNextFreePosition() END IF ! Species(iSpec)%Init(iInit)%ParticleEmissionType.EQ.0 END DO ! Species(iSpec)%NumberOfInits @@ -889,12 +898,10 @@ SUBROUTINE DetermineInitialParticleNumber() / Species(iSpec)%MacroParticleFactor * (Species(iSpec)%Init(iInit)%RadiusIC**3 * 4./3. * PI)) END IF ELSE - CALL abort(__STAMP__, & - 'BaseVectors are parallel or zero!') + CALL abort(__STAMP__,'BaseVectors are parallel or zero!') END IF CASE DEFAULT - CALL abort(__STAMP__, & - 'Given velocity distribution is not supported with the SpaceIC cuboid/sphere/cylinder!') + CALL abort(__STAMP__,'Given velocity distribution is not supported with the SpaceIC cuboid/sphere/cylinder!') END SELECT ! Species(iSpec)%Init(iInit)%SpaceIC CASE('cell_local') SELECT CASE(TRIM(Species(iSpec)%Init(iInit)%velocityDistribution)) @@ -926,8 +933,8 @@ SUBROUTINE DetermineInitialParticleNumber() #else insertParticles = insertParticles + INT(Species(iSpec)%Init(iInit)%ParticleNumber,8) #endif - END DO -END DO + END DO ! iInit = 1, Species(iSpec)%NumberOfInits +END DO ! iSpec=1,nSpecies IF (insertParticles.GT.PDM%maxParticleNumber) THEN IPWRITE(UNIT_stdOut,*)' Maximum particle number : ',PDM%maxParticleNumber diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index ea6ce0c7a..a673baede 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -33,8 +33,12 @@ MODULE MOD_part_pos_and_velo MODULE PROCEDURE SetParticleVelocity END INTERFACE +INTERFACE SetPartPosAndVeloEmissionDistribution + MODULE PROCEDURE SetPartPosAndVeloEmissionDistribution +END INTERFACE + !=================================================================================================================================== -PUBLIC :: SetParticleVelocity, SetParticlePosition +PUBLIC :: SetParticleVelocity, SetParticlePosition, SetPartPosAndVeloEmissionDistribution !=================================================================================================================================== CONTAINS @@ -461,4 +465,76 @@ SUBROUTINE SetParticleVelocity(FractNbr,iInit,NbrOfParticle) END SELECT END SUBROUTINE SetParticleVelocity + +SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) +!=================================================================================================================================== +! Set particle position for processor-local particles (only in processor elements) +!=================================================================================================================================== +! modules +USE MOD_Globals +USE MOD_Globals ,ONLY: abort +USE MOD_part_tools ,ONLY: InitializeParticleMaxwell,InterpolateEmissionDistribution2D +USE MOD_Mesh_Vars ,ONLY: nElems,offsetElem +USE MOD_Particle_Vars ,ONLY: Species, PDM, PartState +USE MOD_Particle_Mesh_Vars ,ONLY: BoundsOfElem_Shared +USE MOD_Particle_Tracking ,ONLY: ParticleInsideCheck +USE MOD_Mesh_Vars ,ONLY: ElemBaryNGeo +USE MOD_Mesh_Tools ,ONLY: GetCNElemID +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim +!---------------------------------------------------------------------------------------------------------------------------------- +! IMPLICIT VARIABLE HANDLING +IMPLICIT NONE +!----------------------------------------------------------------------------------------------------------------------------------- +! INPUT VARIABLES +INTEGER,INTENT(IN) :: iSpec, iInit +!----------------------------------------------------------------------------------------------------------------------------------- +! OUTPUT VARIABLES +INTEGER,INTENT(OUT) :: NbrOfParticle +!----------------------------------------------------------------------------------------------------------------------------------- +! LOCAL VARIABLES +INTEGER :: iElem,iPart,nPart,GlobalElemID +REAL :: iRan, RandomPos(3), MPF +REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values +REAL :: BBoxVolume, origin(3) +LOGICAL :: InsideFlag +!===================================================================================================================================/ +NbrOfParticle = 0 + +DO iElem = 1, nElems + GlobalElemID = iElem + offsetElem + origin(1:3) = ElemBaryNGeo(:,GetCNElemID(GlobalElemID)) + ASSOCIATE( Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z + BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1)) + CALL RANDOM_NUMBER(iRan) + MPF = Species(iSpec)%MacroParticleFactor + SELECT CASE(EmissionDistributionDim) + CASE(1) + CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') + CASE(2) + ! Density field from .h5 file that is interpolated to the element origin (bilinear interpolation) + PartDens(1:3) = InterpolateEmissionDistribution2D(origin(1:3),dimLower=3,dimUpper=3,transformation=.FALSE.) + CASE(3) + CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') + END SELECT + nPart = INT(PartDens(1) * BBoxVolume / MPF + iRan) + DO iPart = 1, nPart + InsideFlag = .FALSE. + CALL RANDOM_NUMBER(RandomPos) + RandomPos(1:3) = Bounds(1,1:3) + RandomPos(1:3)*(Bounds(2,1:3)-Bounds(1,1:3)) + InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) + ! Exclude particles outside of the element + IF (InsideFlag) THEN + NbrOfParticle = NbrOfParticle + 1 + IF(NbrOfParticle.GE.PDM%maxParticleNumber) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',NbrOfParticle) + PartState(1:3,NbrOfParticle) = origin(1:3) ! Little hack: store element centre temporarily in PartPos + CALL InitializeParticleMaxwell(NbrOfParticle,iSpec,iElem,Mode=2) + PartState(1:3,NbrOfParticle) = RandomPos(1:3) + END IF + END DO ! nPart + + END ASSOCIATE +END DO ! iElem = 1, nElems +END SUBROUTINE SetPartPosAndVeloEmissionDistribution + + END MODULE MOD_part_pos_and_velo diff --git a/src/particles/particle_tools.f90 b/src/particles/particle_tools.f90 index 451c15ccf..6b1cc433d 100644 --- a/src/particles/particle_tools.f90 +++ b/src/particles/particle_tools.f90 @@ -53,6 +53,10 @@ MODULE MOD_part_tools MODULE PROCEDURE StoreLostParticleProperties END INTERFACE +INTERFACE InterpolateEmissionDistribution2D + MODULE PROCEDURE InterpolateEmissionDistribution2D +END INTERFACE + !----------------------------------------------------------------------------------------------------------------------------------- ! GLOBAL VARIABLES !----------------------------------------------------------------------------------------------------------------------------------- @@ -62,6 +66,7 @@ MODULE MOD_part_tools PUBLIC :: isPushParticle, isDepositParticle, isInterpolateParticle, StoreLostParticleProperties, BuildTransGaussNums PUBLIC :: CalcXiElec,ParticleOnProc, CalcERot_particle, CalcEVib_particle, CalcEElec_particle, CalcVelocity_maxwell_particle PUBLIC :: InitializeParticleMaxwell +PUBLIC :: InterpolateEmissionDistribution2D !=================================================================================================================================== CONTAINS @@ -997,6 +1002,7 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) USE MOD_DSMC_Vars ,ONLY: DSMC, PartStateIntEn, CollisMode, SpecDSMC, RadialWeighting, AmbipolElecVelo USE MOD_Restart_Vars ,ONLY: MacroRestartValues USE MOD_Particle_VarTimeStep ,ONLY: CalcVarTimeStep +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim !USE MOD_part_tools ,ONLY: CalcRadWeightMPF, CalcEElec_particle, CalcEVib_particle, CalcERot_particle !USE MOD_part_tools ,ONLY: CalcVelocity_maxwell_particle !----------------------------------------------------------------------------------------------------------------------------------- @@ -1036,6 +1042,20 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) IF(DSMC%DoAmbipolarDiff) CALL abort(__STAMP__,'DSMC%DoAmbipolarDiff=T'//TRIM(hilf)) IF(VarTimeStep%UseVariableTimeStep) CALL abort(__STAMP__,'VarTimeStep%UseVariableTimeStep=T'//TRIM(hilf)) IF(RadialWeighting%DoRadialWeighting) CALL abort(__STAMP__,'RadialWeighting%DoRadialWeighting=T'//TRIM(hilf)) + ! Check dimensionality of data + SELECT CASE(EmissionDistributionDim) + CASE(1) + CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') + CASE(2) + ! Density field from .h5 file that is interpolated to the element origin (bilinear interpolation) + T(1:3) = InterpolateEmissionDistribution2D(PartState(1:3,iPart),dimLower=4,dimUpper=4,transformation=.FALSE.) + v(1:3) = InterpolateEmissionDistribution2D(PartState(1:3,iPart),dimLower=5,dimUpper=6,transformation=.TRUE.) + CASE(3) + CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') + END SELECT + Tvib = T(1) + Trot = T(1) + Telec = T(1) CASE DEFAULT CALL abort(__STAMP__,'InitializeParticleMaxwell: Mode option is unknown. Mode=',IntInfoOpt=Mode) END SELECT @@ -1084,4 +1104,105 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) END SUBROUTINE InitializeParticleMaxwell +PPURE FUNCTION InterpolateEmissionDistribution2D(Pos,dimLower,dimUpper,transformation) +!=================================================================================================================================== +!> This function returns a scalar property or a vector property (transformation from cylindrical coordinates to Cartesian required!) +!> Interpolates the variable external field to the r- and z-position via bilinear interpolation +!> +!> 1.2 --------- 2.2 +!> | | +!> r | | +!> | | +!> 1.1 --------- 2.1 +!> z +!=================================================================================================================================== +! MODULES +USE MOD_Globals +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution !< data in 2D cylindrical coordinates +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDelta +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN +! IMPLICIT VARIABLE HANDLING +IMPLICIT NONE +!----------------------------------------------------------------------------------------------------------------------------------- +! INPUT VARIABLES +REAL,INTENT(IN) :: Pos(1:3) !< coordinate +LOGICAL,INTENT(IN) :: transformation !< transform from f(r,z) to f(x,y,z) +INTEGER,INTENT(IN) :: dimLower,dimUpper !< lower and upper dimension of variables in EmissionDistribution +!----------------------------------------------------------------------------------------------------------------------------------- +! OUTPUT VARIABLES +REAL :: InterpolateEmissionDistribution2D(dimLower:dimLower+2) !< 3D Cartesian vector +!----------------------------------------------------------------------------------------------------------------------------------- +! LOCAL VARIABLES +INTEGER :: iPos,jPos !< index in array (equidistant subdivision assumed) +REAL :: f(dimLower:dimUpper) +REAL :: r,delta,mat(2,2),dx(1:2),dy(1:2),vec(1:2) +INTEGER :: idx1,idx2,idx3,idx4,i +!=================================================================================================================================== +ASSOCIATE(& + x => Pos(1) ,& + y => Pos(2) ,& + z => Pos(3) & + ) + r = SQRT(x**2+y**2) + iPos = INT((r-EmissionDistribution(1,1))/EmissionDistributionDelta(1)) + 1 + jPos = INT((z-EmissionDistribution(2,1))/EmissionDistributionDelta(2)) + 1 + + + IF(r.GT.EmissionDistributionMax(1))THEN + InterpolateEmissionDistribution2D = 0. + ELSEIF(r.LT.EmissionDistributionMin(1))THEN + InterpolateEmissionDistribution2D = 0. + ELSEIF(z.GT.EmissionDistributionMax(2))THEN + InterpolateEmissionDistribution2D = 0. + ELSEIF(z.LT.EmissionDistributionMin(2))THEN + InterpolateEmissionDistribution2D = 0. + ELSE + ! 1.1 + idx1 = (iPos-1)*EmissionDistributionN(1) + jPos + ! 2.1 + idx2 = (iPos-1)*EmissionDistributionN(1) + jPos + 1 + ! 1.2 + idx3 = iPos*EmissionDistributionN(1) + jPos + ! 2.2 + idx4 = iPos*EmissionDistributionN(1) + jPos + 1 + + ! Interpolate + delta = EmissionDistributionDelta(1)*EmissionDistributionDelta(2) + delta = 1./delta + + dx(1) = EmissionDistribution(1,idx4)-r + dx(2) = EmissionDistributionDelta(1) - dx(1) + + dy(1) = EmissionDistribution(2,idx4)-z + dy(2) = EmissionDistributionDelta(2) - dy(1) + + DO i = dimLower, dimUpper + mat(1,1) = EmissionDistribution(i,idx1) + mat(2,1) = EmissionDistribution(i,idx2) + mat(1,2) = EmissionDistribution(i,idx3) + mat(2,2) = EmissionDistribution(i,idx4) + + vec(1) = dx(1) + vec(2) = dx(2) + f(i) = delta * DOT_PRODUCT( vec, MATMUL(mat, (/dy(1),dy(2)/) ) ) + END DO ! i = dimLower, dimUpper + + ! Transform from Br, Bz to Bx, By, Bz + IF(transformation)THEN + r=1./r + InterpolateEmissionDistribution2D(dimLower) = f(dimLower)*x*r + InterpolateEmissionDistribution2D(dimLower+1) = f(dimLower)*y*r + InterpolateEmissionDistribution2D(dimLower+2) = f(dimUpper) + ELSE + InterpolateEmissionDistribution2D(dimLower:dimUpper) = f(dimLower:dimUpper) + InterpolateEmissionDistribution2D(dimLower+1) = InterpolateEmissionDistribution2D(dimLower) + InterpolateEmissionDistribution2D(dimLower+2) = InterpolateEmissionDistribution2D(dimLower) + END IF ! transformation + END IF ! r.GT.EmissionDistributionMax(1) +END ASSOCIATE + +END FUNCTION InterpolateEmissionDistribution2D + + END MODULE MOD_part_tools From 84e129bed09512fb836c95f07c85616799a3dcbd Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 5 Oct 2022 21:31:23 +0200 Subject: [PATCH 06/36] Particle emission via 'EmissionDistribution' now working for multiple species and inits. --- .../parameter.ini | 12 +++++------ .../emission/particle_emission_init.f90 | 21 ++++++++++++------- .../emission/particle_emission_vars.f90 | 2 +- .../particle_position_and_velocity.f90 | 15 ++++++------- src/particles/particle_tools.f90 | 16 ++++++++------ 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini index e31b07950..d5ea88999 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini @@ -28,8 +28,8 @@ TrackingMethod = refmapping!,tracing,triatracking ! =============================================================================== ! ! CALCULATION ! =============================================================================== ! -tend = 1.0E-12 -Analyze_dt = 1.0E-12 +tend = 1.0E-11 +Analyze_dt = 1.0E-11 CFLscale = 0.9 ! Scaling of theoretical CFL number c_corr = 1 @@ -53,7 +53,7 @@ Particles-MPIWeight = 0.01 ! PARTICLES ! =============================================================================== ! Part-maxParticleNumber = 15000 -Part-nSpecies = 1 +Part-nSpecies = 2 Part-nBounds = 1 Part-Boundary1-SourceName = BC_absorbing Part-Boundary1-Condition = reflective @@ -75,7 +75,7 @@ Part-FileNameEmissionDistribution = reggie-linear-rot-symmetry-species-init.h5 ! =============================================================================== ! Part-Species1-ChargeIC = -1.60217653E-19 Part-Species1-MassIC = 9.1093826E-31 -Part-Species1-MacroParticleFactor = 1E12 +Part-Species1-MacroParticleFactor = 2E12 Part-Species1-nInits = 1 @@ -83,11 +83,11 @@ Part-Species1-Init1-SpaceIC = EmissionDistribution Part-Species1-Init1-EmissionDistributionName = electron ! =============================================================================== ! -! Species3 | HeIon +! Species2 | HeIon ! =============================================================================== ! Part-Species2-ChargeIC = 1.60217653E-19 Part-Species2-MassIC = 6.645565470903E-027 -Part-Species2-MacroParticleFactor = 1E12 +Part-Species2-MacroParticleFactor = 2E12 Part-Species2-nInits = 1 diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index 3526403f4..2d47b99d7 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -1020,11 +1020,12 @@ SUBROUTINE ReadUseEmissionDistribution() USE MOD_Globals USE MOD_Particle_Emission_Vars ,ONLY: FileNameEmissionDistribution USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim,EmissionDistributionAxisSym -USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution,EmissionDistributionDelta,EmissionDistributionDim +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDelta,EmissionDistributionDim USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionRadInd,EmissionDistributionAxisDir USE MOD_HDF5_Input_Field ,ONLY: ReadExternalFieldFromHDF5 +USE MOD_Particle_Vars ,ONLY: Species,nSpecies #if USE_LOADBALANCE USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance #endif /*USE_LOADBALANCE*/ @@ -1038,6 +1039,7 @@ SUBROUTINE ReadUseEmissionDistribution() ! LOCAL VARIABLES INTEGER,PARAMETER :: lenmin=4 INTEGER :: lenstr +INTEGER :: iSpec,iInit !=================================================================================================================================== LBWRITE(UNIT_stdOut,'(A,3X,A,65X,A)') ' INITIALIZATION OF EMISSION DISTRIBUTION FOR PARTICLES ' @@ -1050,18 +1052,23 @@ SUBROUTINE ReadUseEmissionDistribution() ! Check file ending, either .csv or .h5 IF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+2:lenstr)).EQ.'.h5')THEN - CALL ReadExternalFieldFromHDF5('electron',& - EmissionDistribution , EmissionDistributionDelta , FileNameEmissionDistribution , EmissionDistributionDim , & - EmissionDistributionAxisSym , EmissionDistributionRadInd , EmissionDistributionAxisDir , EmissionDistributionMin , & - EmissionDistributionMax , EmissionDistributionN) + DO iSpec = 1,nSpecies + DO iInit = 1, Species(iSpec)%NumberOfInits + IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN + CALL ReadExternalFieldFromHDF5(TRIM(Species(iSpec)%Init(iInit)%EmissionDistributionName) ,& + Species(iSpec)%Init(iInit)%EmissionDistribution , EmissionDistributionDelta ,& + FileNameEmissionDistribution , EmissionDistributionDim , EmissionDistributionAxisSym , EmissionDistributionRadInd ,& + EmissionDistributionAxisDir , EmissionDistributionMin , EmissionDistributionMax , EmissionDistributionN ) + IF(.NOT.ALLOCATED(Species(iSpec)%Init(iInit)%EmissionDistribution)) CALL abort(__STAMP__,"Failed to load data from: "//TRIM(FileNameEmissionDistribution)) + END IF ! TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution' + END DO ! iInit = 1, Species(iSpec)%NumberOfInits + END DO ! iSpec = 1,nSpecies ELSEIF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+1:lenstr)).EQ.'.csv')THEN CALL abort(__STAMP__,'ReadUseEmissionDistribution(): Read-in from .csv is not implemented') ELSE CALL abort(__STAMP__,"Unrecognised file format for : "//TRIM(FileNameEmissionDistribution)) END IF -IF(.NOT.ALLOCATED(EmissionDistribution)) CALL abort(__STAMP__,"Failed to load data from: "//TRIM(FileNameEmissionDistribution)) - LBWRITE(UNIT_stdOut,'(A)')' ...EMISSION DISTRIBUTION INITIALIZATION DONE' END SUBROUTINE ReadUseEmissionDistribution diff --git a/src/particles/emission/particle_emission_vars.f90 b/src/particles/emission/particle_emission_vars.f90 index e078ad93f..d87871b96 100644 --- a/src/particles/emission/particle_emission_vars.f90 +++ b/src/particles/emission/particle_emission_vars.f90 @@ -119,6 +119,7 @@ MODULE MOD_Particle_Emission_Vars INTEGER :: BGGRegion ! Region number to be used for the species init !=== Emission distribution CHARACTER(30) :: EmissionDistributionName ! Species name, e.g., "electron" or "ArIon1" for particle emission + REAL,ALLOCATABLE :: EmissionDistribution(:,:) !< pos (r,z or x,y,z) and particle properties (n, T, vx, vy, vz) END TYPE tInit ! 2D Landmark @@ -142,7 +143,6 @@ MODULE MOD_Particle_Emission_Vars INTEGER :: BulkElectronTempSpecID ! Species ID (electron) for Automatic bulk electron calculation ! Emission distribution LOGICAL :: UseEmissionDistribution !< Flag for activation particle emission by interpolation n, T and v (equidistant) -REAL,ALLOCATABLE :: EmissionDistribution(:,:) !< pos (r,z or x,y,z) and particle properties (n, T, vx, vy, vz) CHARACTER(255) :: FileNameEmissionDistribution !< File name form which the data is read INTEGER :: EmissionDistributionDim !< Spatial dimension of variable external field data: 1D, 2D or 3D LOGICAL :: EmissionDistributionAxisSym !< True if the data is axis symmetric, e.g., B(r,z) diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index a673baede..4521683bc 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -492,7 +492,7 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) INTEGER,INTENT(OUT) :: NbrOfParticle !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -INTEGER :: iElem,iPart,nPart,GlobalElemID +INTEGER :: iElem,iPart,nPart,GlobalElemID,PositionNbr REAL :: iRan, RandomPos(3), MPF REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values REAL :: BBoxVolume, origin(3) @@ -502,7 +502,7 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) DO iElem = 1, nElems GlobalElemID = iElem + offsetElem - origin(1:3) = ElemBaryNGeo(:,GetCNElemID(GlobalElemID)) + origin(1:3) = ElemBaryNGeo(:,iElem) ASSOCIATE( Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1)) CALL RANDOM_NUMBER(iRan) @@ -512,7 +512,7 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') CASE(2) ! Density field from .h5 file that is interpolated to the element origin (bilinear interpolation) - PartDens(1:3) = InterpolateEmissionDistribution2D(origin(1:3),dimLower=3,dimUpper=3,transformation=.FALSE.) + PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,origin(1:3),dimLower=3,dimUpper=3,transformation=.FALSE.) CASE(3) CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') END SELECT @@ -525,10 +525,11 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) ! Exclude particles outside of the element IF (InsideFlag) THEN NbrOfParticle = NbrOfParticle + 1 - IF(NbrOfParticle.GE.PDM%maxParticleNumber) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',NbrOfParticle) - PartState(1:3,NbrOfParticle) = origin(1:3) ! Little hack: store element centre temporarily in PartPos - CALL InitializeParticleMaxwell(NbrOfParticle,iSpec,iElem,Mode=2) - PartState(1:3,NbrOfParticle) = RandomPos(1:3) + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) + IF(PositionNbr.GE.PDM%maxParticleNumber) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + PartState(1:3,PositionNbr) = origin(1:3) ! Little hack: store element centre temporarily in PartPos + CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) + PartState(1:3,PositionNbr) = RandomPos(1:3) END IF END DO ! nPart diff --git a/src/particles/particle_tools.f90 b/src/particles/particle_tools.f90 index 6b1cc433d..9d059d23c 100644 --- a/src/particles/particle_tools.f90 +++ b/src/particles/particle_tools.f90 @@ -991,7 +991,7 @@ REAL FUNCTION CalcEElec_particle(iSpec,TempElec,iPart) END FUNCTION CalcEElec_particle -SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) +SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode,iInit) !=================================================================================================================================== !> Initialize a particle from a given macroscopic result, requires the macroscopic velocity, translational and internal temperatures !=================================================================================================================================== @@ -1013,6 +1013,7 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) INTEGER, INTENT(IN) :: iPart, iSpec, iElem INTEGER, INTENT(IN) :: Mode !< 1: Macroscopic restart (data for each element) !< 2: Emission distribution (equidistant data from .h5 file) +INTEGER, INTENT(IN), OPTIONAL :: iInit !< particle emission initialization ID !----------------------------------------------------------------------------------------------------------------------------------- ! OUTPUT VARIABLES !----------------------------------------------------------------------------------------------------------------------------------- @@ -1048,8 +1049,8 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') CASE(2) ! Density field from .h5 file that is interpolated to the element origin (bilinear interpolation) - T(1:3) = InterpolateEmissionDistribution2D(PartState(1:3,iPart),dimLower=4,dimUpper=4,transformation=.FALSE.) - v(1:3) = InterpolateEmissionDistribution2D(PartState(1:3,iPart),dimLower=5,dimUpper=6,transformation=.TRUE.) + T(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,PartState(1:3,iPart),dimLower=4,dimUpper=4,transformation=.FALSE.) + v(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,PartState(1:3,iPart),dimLower=5,dimUpper=6,transformation=.TRUE.) CASE(3) CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') END SELECT @@ -1104,7 +1105,7 @@ SUBROUTINE InitializeParticleMaxwell(iPart,iSpec,iElem,Mode) END SUBROUTINE InitializeParticleMaxwell -PPURE FUNCTION InterpolateEmissionDistribution2D(Pos,dimLower,dimUpper,transformation) +PPURE FUNCTION InterpolateEmissionDistribution2D(iSpec,iInit,Pos,dimLower,dimUpper,transformation) !=================================================================================================================================== !> This function returns a scalar property or a vector property (transformation from cylindrical coordinates to Cartesian required!) !> Interpolates the variable external field to the r- and z-position via bilinear interpolation @@ -1118,7 +1119,8 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(Pos,dimLower,dimUpper,transform !=================================================================================================================================== ! MODULES USE MOD_Globals -USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution !< data in 2D cylindrical coordinates +USE MOD_Particle_Vars ,ONLY: Species +!USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution !< data in 2D cylindrical coordinates USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDelta USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN @@ -1126,6 +1128,7 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(Pos,dimLower,dimUpper,transform IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- ! INPUT VARIABLES +INTEGER,INTENT(IN) :: iSpec, iInit REAL,INTENT(IN) :: Pos(1:3) !< coordinate LOGICAL,INTENT(IN) :: transformation !< transform from f(r,z) to f(x,y,z) INTEGER,INTENT(IN) :: dimLower,dimUpper !< lower and upper dimension of variables in EmissionDistribution @@ -1142,7 +1145,8 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(Pos,dimLower,dimUpper,transform ASSOCIATE(& x => Pos(1) ,& y => Pos(2) ,& - z => Pos(3) & + z => Pos(3) ,& + EmissionDistribution => Species(iSpec)%Init(iInit)%EmissionDistribution& ) r = SQRT(x**2+y**2) iPos = INT((r-EmissionDistribution(1,1))/EmissionDistributionDelta(1)) + 1 From 18f0fa7cc613ab71455e6510bfbd97af656b90a6 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 12 Oct 2022 07:17:37 +0200 Subject: [PATCH 07/36] Minor fixes for restarting from external field-based particle data --- src/io_hdf5/hdf5_input_field.f90 | 4 ++-- src/particles/emission/particle_position_and_velocity.f90 | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/io_hdf5/hdf5_input_field.f90 b/src/io_hdf5/hdf5_input_field.f90 index 352de31ab..36cf77e8a 100644 --- a/src/io_hdf5/hdf5_input_field.f90 +++ b/src/io_hdf5/hdf5_input_field.f90 @@ -221,12 +221,12 @@ SUBROUTINE ReadExternalFieldFromHDF5( DataSet, ExternalField, DeltaExternalField IF(MINVAL(DeltaExternalField(1:2)).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for external field.') ! z-dir: x(1) ! r-dir: x(2) - IF(NbrOfColumns.NE.x(1)*x(2)) CALL abort(__STAMP__,'Wrong number of points in 2D') LBWRITE (UNIT_stdOut,'(A,2(I0,A))') " Read external field with ",x(1)," x ",x(2)," data points" + IF(NbrOfColumns.NE.x(1)*x(2)) CALL abort(__STAMP__,'Wrong number of points in 2D') ELSE + LBWRITE (UNIT_stdOut,'(A,3(I0,A))') " Read external field with ",x(1)," x ",x(2)," x ",x(3)," data points" IF(MINVAL(DeltaExternalField).LT.0.) CALL abort(__STAMP__,'Failed to calculate the deltas for external field.') IF(NbrOfColumns.NE.x(1)*x(2)*x(3)) CALL abort(__STAMP__,'Wrong number of points in 3D') - LBWRITE (UNIT_stdOut,'(A,3(I0,A))') " Read external field with ",x(1)," x ",x(2)," x ",x(3)," data points" END IF ! ExternalFieldDim.EQ.2 END ASSOCIATE diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index 4521683bc..1983d0147 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -526,7 +526,8 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) IF (InsideFlag) THEN NbrOfParticle = NbrOfParticle + 1 PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) - IF(PositionNbr.GE.PDM%maxParticleNumber) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& + (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) PartState(1:3,PositionNbr) = origin(1:3) ! Little hack: store element centre temporarily in PartPos CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) PartState(1:3,PositionNbr) = RandomPos(1:3) From 824fdd8d757c22ab59d578545e2f01f27e9c3a98 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Mon, 24 Oct 2022 22:33:46 +0200 Subject: [PATCH 08/36] high-order particle emission for emission type "EmissionDistribution" using equidistant nodes in each element of order PP_N --- src/equations/maxwell/timeavg.f90 | 12 +- src/equations/poisson/timeavg.f90 | 11 +- .../particle_position_and_velocity.f90 | 139 +++++++++++++++--- 3 files changed, 122 insertions(+), 40 deletions(-) diff --git a/src/equations/maxwell/timeavg.f90 b/src/equations/maxwell/timeavg.f90 index 0d607ee08..b4c62561b 100644 --- a/src/equations/maxwell/timeavg.f90 +++ b/src/equations/maxwell/timeavg.f90 @@ -79,15 +79,8 @@ SUBROUTINE InitTimeAverage() nVarAvg = CountOption('VarNameAvg') nVarFluc = CountOption('VarNameFluc') -IF((nVarAvg.EQ.0).AND.(nVarFluc.EQ.0))THEN - CALL CollectiveStop(__STAMP__, & +IF((nVarAvg.EQ.0).AND.(nVarFluc.EQ.0)) CALL CollectiveStop(__STAMP__,& 'No quantities for time averaging have been specified. Please specify quantities or disable time averaging!') -#if FV_ENABLED -ELSE - CALL CollectiveStop(__STAMP__, & - 'Timeaveraging has not been implemented for FV yet!') -#endif -END IF ! --- Mean values ! Define variables to be averaged @@ -194,8 +187,7 @@ SUBROUTINE InitTimeAverage() SWRITE (*,*) " ChargeDensity-Spec0x" SWRITE (*,*) " ChargeDensityX-Spec0x\n ChargeDensityY-Spec0x\n ChargeDensityZ-Spec0x\n ChargeDensity-Spec0x" #endif /*PARTICLES*/ - CALL CollectiveStop(__STAMP__, & - 'Specified varname does not exist: ' // VarNamesAvgIni(iVar)) + CALL CollectiveStop(__STAMP__, 'Specified varname does not exist: ' // VarNamesAvgIni(iVar)) END IF END DO diff --git a/src/equations/poisson/timeavg.f90 b/src/equations/poisson/timeavg.f90 index d7a738b65..05a66263a 100644 --- a/src/equations/poisson/timeavg.f90 +++ b/src/equations/poisson/timeavg.f90 @@ -79,15 +79,8 @@ SUBROUTINE InitTimeAverage() nVarAvg = CountOption('VarNameAvg') nVarFluc = CountOption('VarNameFluc') -IF((nVarAvg.EQ.0).AND.(nVarFluc.EQ.0))THEN - CALL CollectiveStop(__STAMP__, & - 'No quantities for time averaging have been specified. Please specify quantities or disable time averaging!') -#if FV_ENABLED -ELSE - CALL CollectiveStop(__STAMP__, & - 'Timeaveraging has not been implemented for FV yet!') -#endif -END IF +IF((nVarAvg.EQ.0).AND.(nVarFluc.EQ.0)) CALL CollectiveStop(__STAMP__,& + 'No quantities for time averaging specified. Please specify quantities or disable time averaging!') nSkipAvg=GETINT('nSkipAvg','1') ! Define variables to be averaged diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index a758fce19..9dd6ee680 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -481,8 +481,10 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) ! Set particle position for processor-local particles (only in processor elements) !=================================================================================================================================== ! modules -USE MOD_Globals -USE MOD_Globals ,ONLY: abort +!USE MOD_Globals +USE MOD_Globals ,ONLY: abort,iError +USE MOD_Globals ,ONLY: myrank,UNIT_StdOut,MPI_COMM_WORLD,MPIRoot +USE MOD_PreProc USE MOD_part_tools ,ONLY: InitializeParticleMaxwell,InterpolateEmissionDistribution2D USE MOD_Mesh_Vars ,ONLY: nElems,offsetElem USE MOD_Particle_Vars ,ONLY: Species, PDM, PartState @@ -491,6 +493,20 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) USE MOD_Mesh_Vars ,ONLY: ElemBaryNGeo USE MOD_Mesh_Tools ,ONLY: GetCNElemID USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim + +USE MOD_Interpolation ,ONLY: GetVandermonde,GetNodesAndWeights +USE MOD_Basis ,ONLY: BarycentricWeights +USE MOD_ChangeBasis ,ONLY: ChangeBasis3D +USE MOD_Equation ,ONLY: ExactFunc +USE MOD_Equation_Vars ,ONLY: IniExactFunc +USE MOD_Interpolation_Vars ,ONLY: NAnalyze,Vdm_GaussN_NAnalyze +USE MOD_Mesh_Vars ,ONLY: Elem_xGP,sJ +USE MOD_Particle_Mesh_Vars ,ONLY: MeshVolume +USE MOD_Interpolation_Vars ,ONLY: NodeTypeVISU,NodeType +USE MOD_Mesh_Vars ,ONLY: Vdm_N_EQ +USE MOD_Particle_Mesh_Vars ,ONLY: ElemVolume_Shared +USE MOD_Eval_xyz ,ONLY: TensorProductInterpolation +USE MOD_Mesh_Vars ,ONLY: NGeo,XCL_NGeo,XiCL_NGeo,wBaryCL_NGeo,offsetElem !---------------------------------------------------------------------------------------------------------------------------------- ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE @@ -507,14 +523,39 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values REAL :: BBoxVolume, origin(3) LOGICAL :: InsideFlag +INTEGER :: k,l,m +REAL :: densityGL(1,0:PP_N,0:PP_N,0:PP_N), densityVISU(1,0:PP_N,0:PP_N,0:PP_N) +REAL :: J_NAnalyze(1,0:PP_N,0:PP_N,0:PP_N) +REAL :: IntegrationWeight +REAL :: SumVol,intvol,intBB +REAL :: Coords_NAnalyze(3,0:PP_N,0:PP_N,0:PP_N) +REAL :: xIP_VISU(0:PP_N),wIP_VISU(0:PP_N) +REAL :: RandVal(3),Xi(3),dXi !===================================================================================================================================/ + +!CALL LegendreGaussNodesAndWeights(PP_N,Xi_NGeo,wGP_NGeo) + ! Allocate and determine Vandermonde mapping from NodeType to equidistant (visu) node set + IF(.NOT.ALLOCATED(Vdm_N_EQ))THEN + ALLOCATE(Vdm_N_EQ(0:PP_N,0:PP_N)) + CALL GetVandermonde(PP_N, NodeType, PP_N, NodeTypeVISU, Vdm_N_EQ, modal=.FALSE.) + + END IF ! .NOT.ALLOCATED(Vdm_N_EQ) + + CALL GetNodesAndWeights(PP_N,NodeTypeVISU,xIP_VISU,wIP=wIP_VISU) + !WRITE (*,*) "NodeTypeVISU,xIP_VISU =", NodeTypeVISU,xIP_VISU + !WRITE (*,*) "wIP_VISU =", wIP_VISU + dXi = 2./(PP_N+1.0) + !WRITE (*,*) "dXi =", dXi + + NbrOfParticle = 0 DO iElem = 1, nElems GlobalElemID = iElem + offsetElem - origin(1:3) = ElemBaryNGeo(:,iElem) - ASSOCIATE( Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z - BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1)) + origin(1:3) = ElemBaryNGeo(:,iElem) + ASSOCIATE( & + Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z + BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1) ) CALL RANDOM_NUMBER(iRan) MPF = Species(iSpec)%MacroParticleFactor SELECT CASE(EmissionDistributionDim) @@ -527,22 +568,78 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') END SELECT nPart = INT(PartDens(1) * BBoxVolume / MPF + iRan) - DO iPart = 1, nPart - InsideFlag = .FALSE. - CALL RANDOM_NUMBER(RandomPos) - RandomPos(1:3) = Bounds(1,1:3) + RandomPos(1:3)*(Bounds(2,1:3)-Bounds(1,1:3)) - InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) - ! Exclude particles outside of the element - IF (InsideFlag) THEN - NbrOfParticle = NbrOfParticle + 1 - PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) - IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& - (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) - PartState(1:3,PositionNbr) = origin(1:3) ! Little hack: store element centre temporarily in PartPos - CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) - PartState(1:3,PositionNbr) = RandomPos(1:3) - END IF - END DO ! nPart + intvol = PartDens(1) * ElemVolume_Shared(GetCNElemID(iElem+offSetElem)) + intBB = PartDens(1)* BBoxVolume + + + ! Interpolate the physical position Elem_xGP to the analyze position, needed for exact function + !CALL ChangeBasis3D(3,PP_N,PP_N,Vdm_N_EQ,Elem_xGP(1:3,:,:,:,iElem),Coords_NAnalyze(1:3,:,:,:)) + + + densityGL = -1. + DO m=0,PP_N + DO l=0,PP_N + DO k=0,PP_N + ! Density field from .h5 file that is interpolated to the element xGP (bilinear interpolation) + PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Elem_xGP(1:3,k,l,m,iElem),dimLower=3,dimUpper=3,transformation=.FALSE.) + densityGL(1,k,l,m) = PartDens(1) + !PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Coords_NAnalyze(1:3,k,l,m),dimLower=3,dimUpper=3,transformation=.FALSE.) + !densityVISU(1,k,l,m) = PartDens(1) + END DO ! k + END DO ! l + END DO ! m + ! Interpolate the density at Elem_xGP to the equidistant position, needed for exact function + !WRITE (*,*) "densityGL(1:1,:,:,:) =", densityGL(1:1,:,:,:) + CALL ChangeBasis3D(1,PP_N,PP_N,Vdm_N_EQ,densityGL(1:1,:,:,:),densityVISU(1:1,:,:,:)) + !WRITE (*,*) "densityVISU(1:1,:,:,:) =", densityVISU(1:1,:,:,:) + ! Interpolate the Jacobian to the equidistant grid: be careful we interpolate the inverse of the inverse of the jacobian ;-) + CALL ChangeBasis3D(1,PP_N,PP_N,Vdm_N_EQ,1./sJ(:,:,:,iElem),J_NAnalyze(1:1,:,:,:)) + SumVol = 0. + DO m=0,PP_N + DO l=0,PP_N + DO k=0,PP_N + IntegrationWeight = wIP_VISU(k)*wIP_VISU(l)*wIP_VISU(m)*J_NAnalyze(1,k,l,m) + CALL RANDOM_NUMBER(iRan) + nPart = INT(densityVISU(1,k,l,m)*IntegrationWeight/ MPF + iRan) + + DO iPart = 1, nPart + + CALL RANDOM_NUMBER(RandVal) + Xi(1) = dXi*(k + RandVal(1)) -1.0 + Xi(2) = dXi*(l + RandVal(2)) -1.0 + Xi(3) = dXi*(m + RandVal(3)) -1.0 + ! Get the physical coordinates that correspond to the reference coordinates + CALL TensorProductInterpolation(Xi(1:3),3,NGeo,XiCL_NGeo,wBaryCL_NGeo,XCL_NGeo(1:3,0:NGeo,0:NGeo,0:NGeo,iElem) ,RandomPos(1:3)) !Map into phys. space + !WRITE (*,*) "nPart,Xi,pos =", nPart,Xi,RandomPos(1:3) + + InsideFlag = .TRUE. + + !InsideFlag = .FALSE. + !CALL RANDOM_NUMBER(RandomPos) + !RandomPos(1:3) = Bounds(1,1:3) + RandomPos(1:3)*(Bounds(2,1:3)-Bounds(1,1:3)) + !InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) + ! Exclude particles outside of the element + IF (InsideFlag) THEN + NbrOfParticle = NbrOfParticle + 1 + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) + IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& + (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + PartState(1:3,PositionNbr) = origin(1:3) ! Little hack: store element centre temporarily in PartPos + CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) + PartState(1:3,PositionNbr) = RandomPos(1:3) + !WRITE (*,*) "PartState(1:3,PositionNbr) =", PartState(1:3,PositionNbr) + !IF(myrank.eq.0) read*; CALL MPI_BARRIER(MPI_COMM_WORLD,iError) + END IF + END DO ! nPart + + SumVol = SumVol + densityVISU(1,k,l,m)*IntegrationWeight + END DO ! k + END DO ! l + END DO ! m + + !SWRITE (UNIT_stdOut,'(A,E24.12,E24.12,E24.12)') "SumVol,PartDens(1) * volElem ,intBB=", SumVol,Intvol,intBB + !IF(myrank.eq.0) read*; CALL MPI_BARRIER(MPI_COMM_WORLD,iError) + END ASSOCIATE END DO ! iElem = 1, nElems From a9465719afef9f1025a4caae3d1c03fb49646f46 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 26 Oct 2022 12:51:29 +0200 Subject: [PATCH 09/36] Fixed high-order particle emission for emission type "EmissionDistribution" using equidistant nodes in each element with user-specified polynomial degree "Part-EmissionDistributionN", which has a default value of 2(N+1) with N being the polynomial degree of the solution. --- .../emission/particle_emission_init.f90 | 33 +-- .../emission/particle_emission_vars.f90 | 22 +- .../particle_position_and_velocity.f90 | 226 +++++++----------- src/particles/particle_tools.f90 | 10 +- src/particles/pic/deposition/pic_depo.f90 | 4 +- 5 files changed, 131 insertions(+), 164 deletions(-) diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index b02d908c0..eafe89106 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -169,7 +169,8 @@ SUBROUTINE DefineParametersParticleEmission() CALL prms%CreateRealOption('Part-Species[$]-Init[$]-MacroParticleFactor', 'Emission-specific particle weighting factor: number of simulation particles per real particle',numberedmulti=.TRUE.) ! ====================================== emission distribution ================================================================= CALL prms%CreateStringOption( 'Part-Species[$]-Init[$]-EmissionDistributionName' , 'Name of the species, e.g., "electron" or "ArIon" used for initial emission via interpolation of n, T and v from equidistant field data (no default).' ,numberedmulti=.TRUE.) -CALL prms%CreateStringOption( 'Part-FileNameEmissionDistribution' , 'H5 or CSV file containing the data for initial emission via interpolation of n, T and v from equidistant field data', 'none') +CALL prms%CreateStringOption( 'Part-EmissionDistributionFileName' , 'H5 or CSV file containing the data for initial emission via interpolation of n, T and v from equidistant field data', 'none') +CALL prms%CreateIntOption( 'Part-EmissionDistributionN' , 'Polynomial degree for particle emission in each element. The default value is 2(N+1) with N being the polynomial degree of the solution.') END SUBROUTINE DefineParametersParticleEmission @@ -179,6 +180,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() !=================================================================================================================================== ! MODULES USE MOD_Globals +USE MOD_PreProc USE MOD_Globals_Vars USE MOD_ReadInTools USE MOD_Particle_Vars @@ -197,7 +199,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES INTEGER :: iSpec, iInit -CHARACTER(32) :: hilf, hilf2 +CHARACTER(32) :: hilf, hilf2, DefStr !=================================================================================================================================== ALLOCATE(SpecReset(1:nSpecies)) SpecReset=.FALSE. @@ -447,7 +449,9 @@ SUBROUTINE InitializeVariablesSpeciesInits() !-- Read Emission Distribution stuff IF(UseEmissionDistribution.AND.(.NOT.DoRestart)) THEN - FileNameEmissionDistribution = GETSTR('Part-FileNameEmissionDistribution') + EmissionDistributionFileName = GETSTR('Part-EmissionDistributionFileName') + WRITE(DefStr,'(i4)') 2*(PP_N+1) + EmissionDistributionN = GETINT('Part-EmissionDistributionN', DefStr) CALL ReadUseEmissionDistribution() END IF !SWRITE (*,*) "BARRIER =" @@ -1018,11 +1022,11 @@ SUBROUTINE ReadUseEmissionDistribution() !=================================================================================================================================== ! MODULES USE MOD_Globals -USE MOD_Particle_Emission_Vars ,ONLY: FileNameEmissionDistribution +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionFileName USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim,EmissionDistributionAxisSym USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDelta,EmissionDistributionDim USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin -USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionNum USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionRadInd,EmissionDistributionAxisDir USE MOD_HDF5_Input_Field ,ONLY: ReadExternalFieldFromHDF5 USE MOD_Particle_Vars ,ONLY: Species,nSpecies @@ -1044,29 +1048,30 @@ SUBROUTINE ReadUseEmissionDistribution() LBWRITE(UNIT_stdOut,'(A,3X,A,65X,A)') ' INITIALIZATION OF EMISSION DISTRIBUTION FOR PARTICLES ' ! Check if file exists -IF(.NOT.FILEEXISTS(FileNameEmissionDistribution)) CALL abort(__STAMP__,"File not found: "//TRIM(FileNameEmissionDistribution)) +IF(.NOT.FILEEXISTS(EmissionDistributionFileName)) CALL abort(__STAMP__,"File not found: "//TRIM(EmissionDistributionFileName)) ! Check length of file name -lenstr=LEN(TRIM(FileNameEmissionDistribution)) -IF(lenstr.LT.lenmin) CALL abort(__STAMP__,"File name too short: "//TRIM(FileNameEmissionDistribution)) +lenstr=LEN(TRIM(EmissionDistributionFileName)) +IF(lenstr.LT.lenmin) CALL abort(__STAMP__,"File name too short: "//TRIM(EmissionDistributionFileName)) ! Check file ending, either .csv or .h5 -IF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+2:lenstr)).EQ.'.h5')THEN +IF(TRIM(EmissionDistributionFileName(lenstr-lenmin+2:lenstr)).EQ.'.h5')THEN DO iSpec = 1,nSpecies DO iInit = 1, Species(iSpec)%NumberOfInits IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN CALL ReadExternalFieldFromHDF5(TRIM(Species(iSpec)%Init(iInit)%EmissionDistributionName) ,& Species(iSpec)%Init(iInit)%EmissionDistribution , EmissionDistributionDelta ,& - FileNameEmissionDistribution , EmissionDistributionDim , EmissionDistributionAxisSym , EmissionDistributionRadInd ,& - EmissionDistributionAxisDir , EmissionDistributionMin , EmissionDistributionMax , EmissionDistributionN ) - IF(.NOT.ALLOCATED(Species(iSpec)%Init(iInit)%EmissionDistribution)) CALL abort(__STAMP__,"Failed to load data from: "//TRIM(FileNameEmissionDistribution)) + EmissionDistributionFileName , EmissionDistributionDim , EmissionDistributionAxisSym , EmissionDistributionRadInd ,& + EmissionDistributionAxisDir , EmissionDistributionMin , EmissionDistributionMax , EmissionDistributionNum ) + IF(.NOT.ALLOCATED(Species(iSpec)%Init(iInit)%EmissionDistribution)) CALL abort(__STAMP__,& + "Failed to load data from: "//TRIM(EmissionDistributionFileName)) END IF ! TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution' END DO ! iInit = 1, Species(iSpec)%NumberOfInits END DO ! iSpec = 1,nSpecies -ELSEIF(TRIM(FileNameEmissionDistribution(lenstr-lenmin+1:lenstr)).EQ.'.csv')THEN +ELSEIF(TRIM(EmissionDistributionFileName(lenstr-lenmin+1:lenstr)).EQ.'.csv')THEN CALL abort(__STAMP__,'ReadUseEmissionDistribution(): Read-in from .csv is not implemented') ELSE - CALL abort(__STAMP__,"Unrecognised file format for : "//TRIM(FileNameEmissionDistribution)) + CALL abort(__STAMP__,"Unrecognised file format for : "//TRIM(EmissionDistributionFileName)) END IF LBWRITE(UNIT_stdOut,'(A)')' ...EMISSION DISTRIBUTION INITIALIZATION DONE' diff --git a/src/particles/emission/particle_emission_vars.f90 b/src/particles/emission/particle_emission_vars.f90 index d87871b96..e011464d0 100644 --- a/src/particles/emission/particle_emission_vars.f90 +++ b/src/particles/emission/particle_emission_vars.f90 @@ -141,16 +141,18 @@ MODULE MOD_Particle_Emission_Vars ! to eV for usage in the code OR for neutralization BC (e.g. landmark) LOGICAL :: CalcBulkElectronTemp ! Automatic bulk electron calculation INTEGER :: BulkElectronTempSpecID ! Species ID (electron) for Automatic bulk electron calculation + ! Emission distribution -LOGICAL :: UseEmissionDistribution !< Flag for activation particle emission by interpolation n, T and v (equidistant) -CHARACTER(255) :: FileNameEmissionDistribution !< File name form which the data is read -INTEGER :: EmissionDistributionDim !< Spatial dimension of variable external field data: 1D, 2D or 3D -LOGICAL :: EmissionDistributionAxisSym !< True if the data is axis symmetric, e.g., B(r,z) -INTEGER :: EmissionDistributionRadInd !< Index of radial r-coordinate when using 2D data and axis symmetric -INTEGER :: EmissionDistributionAxisDir !< Direction that is used for the axial symmetric direction (1,2 or 3) -INTEGER :: EmissionDistributionN(1:3) !< Number of points in x, y and z-direction -REAL :: EmissionDistributionMin(1:3) !< Minimum values in x,y,z -REAL :: EmissionDistributionMax(1:3) !< Maximum values in x,y,z -REAL :: EmissionDistributionDelta(1:3) !< equidistant z-spacing for the VariableExternalField (fast computation) +LOGICAL :: UseEmissionDistribution !< Flag for activation particle emission by interpolation n, T and v (equidistant) +CHARACTER(255) :: EmissionDistributionFileName !< File name form which the data is read +INTEGER :: EmissionDistributionN !< Polynomial degree for particle emission in each element +INTEGER :: EmissionDistributionDim !< Spatial dimension of variable external field data: 1D, 2D or 3D +LOGICAL :: EmissionDistributionAxisSym !< True if the data is axis symmetric, e.g., B(r,z) +INTEGER :: EmissionDistributionRadInd !< Index of radial r-coordinate when using 2D data and axis symmetric +INTEGER :: EmissionDistributionAxisDir !< Direction that is used for the axial symmetric direction (1,2 or 3) +INTEGER :: EmissionDistributionNum(1:3) !< Number of points in x, y and z-direction +REAL :: EmissionDistributionMin(1:3) !< Minimum values in x,y,z +REAL :: EmissionDistributionMax(1:3) !< Maximum values in x,y,z +REAL :: EmissionDistributionDelta(1:3)!< equidistant z-spacing for the VariableExternalField (fast computation) !=================================================================================================================================== END MODULE MOD_Particle_Emission_Vars diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index 9dd6ee680..3cc67a0ba 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -482,31 +482,22 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) !=================================================================================================================================== ! modules !USE MOD_Globals -USE MOD_Globals ,ONLY: abort,iError -USE MOD_Globals ,ONLY: myrank,UNIT_StdOut,MPI_COMM_WORLD,MPIRoot USE MOD_PreProc +USE MOD_Globals ,ONLY: myrank,UNIT_StdOut,MPI_COMM_WORLD,abort USE MOD_part_tools ,ONLY: InitializeParticleMaxwell,InterpolateEmissionDistribution2D USE MOD_Mesh_Vars ,ONLY: nElems,offsetElem USE MOD_Particle_Vars ,ONLY: Species, PDM, PartState -USE MOD_Particle_Mesh_Vars ,ONLY: BoundsOfElem_Shared USE MOD_Particle_Tracking ,ONLY: ParticleInsideCheck -USE MOD_Mesh_Vars ,ONLY: ElemBaryNGeo USE MOD_Mesh_Tools ,ONLY: GetCNElemID -USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim - +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim, EmissionDistributionN USE MOD_Interpolation ,ONLY: GetVandermonde,GetNodesAndWeights USE MOD_Basis ,ONLY: BarycentricWeights -USE MOD_ChangeBasis ,ONLY: ChangeBasis3D -USE MOD_Equation ,ONLY: ExactFunc -USE MOD_Equation_Vars ,ONLY: IniExactFunc -USE MOD_Interpolation_Vars ,ONLY: NAnalyze,Vdm_GaussN_NAnalyze -USE MOD_Mesh_Vars ,ONLY: Elem_xGP,sJ -USE MOD_Particle_Mesh_Vars ,ONLY: MeshVolume +USE MOD_ChangeBasis ,ONLY: ChangeBasis3D +USE MOD_Equation ,ONLY: ExactFunc +USE MOD_Mesh_Vars ,ONLY: Elem_xGP,sJ USE MOD_Interpolation_Vars ,ONLY: NodeTypeVISU,NodeType -USE MOD_Mesh_Vars ,ONLY: Vdm_N_EQ -USE MOD_Particle_Mesh_Vars ,ONLY: ElemVolume_Shared -USE MOD_Eval_xyz ,ONLY: TensorProductInterpolation -USE MOD_Mesh_Vars ,ONLY: NGeo,XCL_NGeo,XiCL_NGeo,wBaryCL_NGeo,offsetElem +USE MOD_Eval_xyz ,ONLY: TensorProductInterpolation +USE MOD_Mesh_Vars ,ONLY: NGeo,XCL_NGeo,XiCL_NGeo,wBaryCL_NGeo,offsetElem !---------------------------------------------------------------------------------------------------------------------------------- ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE @@ -518,130 +509,99 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) INTEGER,INTENT(OUT) :: NbrOfParticle !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -INTEGER :: iElem,iPart,nPart,GlobalElemID,PositionNbr -REAL :: iRan, RandomPos(3), MPF -REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values -REAL :: BBoxVolume, origin(3) -LOGICAL :: InsideFlag -INTEGER :: k,l,m -REAL :: densityGL(1,0:PP_N,0:PP_N,0:PP_N), densityVISU(1,0:PP_N,0:PP_N,0:PP_N) -REAL :: J_NAnalyze(1,0:PP_N,0:PP_N,0:PP_N) -REAL :: IntegrationWeight -REAL :: SumVol,intvol,intBB -REAL :: Coords_NAnalyze(3,0:PP_N,0:PP_N,0:PP_N) -REAL :: xIP_VISU(0:PP_N),wIP_VISU(0:PP_N) -REAL :: RandVal(3),Xi(3),dXi +INTEGER :: iElem,iPart,nPart,GlobalElemID,PositionNbr +REAL :: iRan, RandomPos(3), MPF +REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values +LOGICAL :: InsideFlag +INTEGER :: k,l,m +REAL :: densityVISU(1,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) +REAL :: J_NAnalyze(1,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) +REAL :: IntegrationWeight +REAL :: Coords_NAnalyze(3,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) +REAL :: xIP_VISU(0:EmissionDistributionN),wIP_VISU(0:EmissionDistributionN) +REAL :: RandVal(3),Xi(3) +REAL :: Vdm_N_EQ_emission(0:EmissionDistributionN,0:EmissionDistributionN) ! < Vandermonde mapping from NodeType to equidistant (visu) node set !===================================================================================================================================/ -!CALL LegendreGaussNodesAndWeights(PP_N,Xi_NGeo,wGP_NGeo) - ! Allocate and determine Vandermonde mapping from NodeType to equidistant (visu) node set - IF(.NOT.ALLOCATED(Vdm_N_EQ))THEN - ALLOCATE(Vdm_N_EQ(0:PP_N,0:PP_N)) - CALL GetVandermonde(PP_N, NodeType, PP_N, NodeTypeVISU, Vdm_N_EQ, modal=.FALSE.) - - END IF ! .NOT.ALLOCATED(Vdm_N_EQ) - - CALL GetNodesAndWeights(PP_N,NodeTypeVISU,xIP_VISU,wIP=wIP_VISU) - !WRITE (*,*) "NodeTypeVISU,xIP_VISU =", NodeTypeVISU,xIP_VISU - !WRITE (*,*) "wIP_VISU =", wIP_VISU - dXi = 2./(PP_N+1.0) - !WRITE (*,*) "dXi =", dXi - +! Allocate and determine Vandermonde mapping from NodeType to equidistant (visu) node set +CALL GetVandermonde(PP_N, NodeType, EmissionDistributionN, NodeTypeVISU, Vdm_N_EQ_emission, modal=.FALSE.) +CALL GetNodesAndWeights(EmissionDistributionN, NodeTypeVISU, xIP_VISU, wIP=wIP_VISU) NbrOfParticle = 0 +MPF = Species(iSpec)%MacroParticleFactor DO iElem = 1, nElems GlobalElemID = iElem + offsetElem - origin(1:3) = ElemBaryNGeo(:,iElem) - ASSOCIATE( & - Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z - BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1) ) - CALL RANDOM_NUMBER(iRan) - MPF = Species(iSpec)%MacroParticleFactor - SELECT CASE(EmissionDistributionDim) - CASE(1) - CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') - CASE(2) - ! Density field from .h5 file that is interpolated to the element origin (bilinear interpolation) - PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,origin(1:3),dimLower=3,dimUpper=3,transformation=.FALSE.) - CASE(3) - CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') - END SELECT - nPart = INT(PartDens(1) * BBoxVolume / MPF + iRan) - intvol = PartDens(1) * ElemVolume_Shared(GetCNElemID(iElem+offSetElem)) - intBB = PartDens(1)* BBoxVolume - - - ! Interpolate the physical position Elem_xGP to the analyze position, needed for exact function - !CALL ChangeBasis3D(3,PP_N,PP_N,Vdm_N_EQ,Elem_xGP(1:3,:,:,:,iElem),Coords_NAnalyze(1:3,:,:,:)) - - - densityGL = -1. - DO m=0,PP_N - DO l=0,PP_N - DO k=0,PP_N - ! Density field from .h5 file that is interpolated to the element xGP (bilinear interpolation) - PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Elem_xGP(1:3,k,l,m,iElem),dimLower=3,dimUpper=3,transformation=.FALSE.) - densityGL(1,k,l,m) = PartDens(1) - !PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Coords_NAnalyze(1:3,k,l,m),dimLower=3,dimUpper=3,transformation=.FALSE.) - !densityVISU(1,k,l,m) = PartDens(1) - END DO ! k - END DO ! l - END DO ! m - ! Interpolate the density at Elem_xGP to the equidistant position, needed for exact function - !WRITE (*,*) "densityGL(1:1,:,:,:) =", densityGL(1:1,:,:,:) - CALL ChangeBasis3D(1,PP_N,PP_N,Vdm_N_EQ,densityGL(1:1,:,:,:),densityVISU(1:1,:,:,:)) - !WRITE (*,*) "densityVISU(1:1,:,:,:) =", densityVISU(1:1,:,:,:) - ! Interpolate the Jacobian to the equidistant grid: be careful we interpolate the inverse of the inverse of the jacobian ;-) - CALL ChangeBasis3D(1,PP_N,PP_N,Vdm_N_EQ,1./sJ(:,:,:,iElem),J_NAnalyze(1:1,:,:,:)) - SumVol = 0. - DO m=0,PP_N - DO l=0,PP_N - DO k=0,PP_N - IntegrationWeight = wIP_VISU(k)*wIP_VISU(l)*wIP_VISU(m)*J_NAnalyze(1,k,l,m) - CALL RANDOM_NUMBER(iRan) - nPart = INT(densityVISU(1,k,l,m)*IntegrationWeight/ MPF + iRan) - - DO iPart = 1, nPart - - CALL RANDOM_NUMBER(RandVal) - Xi(1) = dXi*(k + RandVal(1)) -1.0 - Xi(2) = dXi*(l + RandVal(2)) -1.0 - Xi(3) = dXi*(m + RandVal(3)) -1.0 - ! Get the physical coordinates that correspond to the reference coordinates - CALL TensorProductInterpolation(Xi(1:3),3,NGeo,XiCL_NGeo,wBaryCL_NGeo,XCL_NGeo(1:3,0:NGeo,0:NGeo,0:NGeo,iElem) ,RandomPos(1:3)) !Map into phys. space - !WRITE (*,*) "nPart,Xi,pos =", nPart,Xi,RandomPos(1:3) - - InsideFlag = .TRUE. - - !InsideFlag = .FALSE. - !CALL RANDOM_NUMBER(RandomPos) - !RandomPos(1:3) = Bounds(1,1:3) + RandomPos(1:3)*(Bounds(2,1:3)-Bounds(1,1:3)) - !InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) - ! Exclude particles outside of the element - IF (InsideFlag) THEN - NbrOfParticle = NbrOfParticle + 1 - PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) - IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& - (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) - PartState(1:3,PositionNbr) = origin(1:3) ! Little hack: store element centre temporarily in PartPos - CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) - PartState(1:3,PositionNbr) = RandomPos(1:3) - !WRITE (*,*) "PartState(1:3,PositionNbr) =", PartState(1:3,PositionNbr) - !IF(myrank.eq.0) read*; CALL MPI_BARRIER(MPI_COMM_WORLD,iError) - END IF - END DO ! nPart - - SumVol = SumVol + densityVISU(1,k,l,m)*IntegrationWeight - END DO ! k - END DO ! l - END DO ! m - - !SWRITE (UNIT_stdOut,'(A,E24.12,E24.12,E24.12)') "SumVol,PartDens(1) * volElem ,intBB=", SumVol,Intvol,intBB - !IF(myrank.eq.0) read*; CALL MPI_BARRIER(MPI_COMM_WORLD,iError) - - - END ASSOCIATE + SELECT CASE(EmissionDistributionDim) + CASE(1) ! 1D + CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') + CASE(2) ! 2D + + ! Interpolate the physical position Elem_xGP to the analyze position, needed for exact function + CALL ChangeBasis3D(3,PP_N,EmissionDistributionN,Vdm_N_EQ_emission,Elem_xGP(1:3,:,:,:,iElem),Coords_NAnalyze(1:3,:,:,:)) + + densityVISU = -1. + DO m=0,EmissionDistributionN + DO l=0,EmissionDistributionN + DO k=0,EmissionDistributionN + ! Density field from .h5 data that is interpolated to the equidistant interpolation points (bilinear interpolation) + PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Coords_NAnalyze(1:3,k,l,m),dimLower=3,dimUpper=3,& + transformation=.FALSE.) + densityVISU(1,k,l,m) = PartDens(1) + END DO ! k + END DO ! l + END DO ! m + + ! Interpolate the Jacobian to the equidistant grid: be careful we interpolate the inverse of the inverse of the jacobian ;-) + CALL ChangeBasis3D(1, PP_N, EmissionDistributionN, Vdm_N_EQ_emission, 1./sJ(:,:,:,iElem), J_NAnalyze(1:1,:,:,:)) + + ! Loop over all interpolation points + DO m=0,EmissionDistributionN + DO l=0,EmissionDistributionN + DO k=0,EmissionDistributionN + IntegrationWeight = wIP_VISU(k)*wIP_VISU(l)*wIP_VISU(m)*J_NAnalyze(1,k,l,m) + + ! Add noise via random number + CALL RANDOM_NUMBER(iRan) + nPart = INT(densityVISU(1,k,l,m)*IntegrationWeight/MPF + iRan) + + ! Loop over all newly created particles + DO iPart = 1, nPart + CALL RANDOM_NUMBER(RandVal) + Xi(1) = -1.0 + SUM(wIP_VISU(0:k-1)) + wIP_VISU(k) * RandVal(1) + Xi(2) = -1.0 + SUM(wIP_VISU(0:l-1)) + wIP_VISU(l) * RandVal(2) + Xi(3) = -1.0 + SUM(wIP_VISU(0:m-1)) + wIP_VISU(m) * RandVal(3) + IF(ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0))THEN + IPWRITE(UNIT_StdOut,*) "Xi =", Xi + CALL abort(__STAMP__,'xi out of range') + END IF ! ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0) + ! Get the physical coordinates that correspond to the reference coordinates + CALL TensorProductInterpolation(Xi(1:3),3,NGeo,XiCL_NGeo,wBaryCL_NGeo,XCL_NGeo(1:3,0:NGeo,0:NGeo,0:NGeo,iElem),& + RandomPos(1:3)) !Map into phys. space + + !InsideFlag = .FALSE. + !InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) + InsideFlag = .TRUE. + + ! Exclude particles outside of the element + IF (InsideFlag) THEN + NbrOfParticle = NbrOfParticle + 1 + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) + IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& + (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + PartState(1:3,PositionNbr) = RandomPos(1:3) ! Little hack: store new particle position temporarily in PartState + CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) + PartState(1:3,PositionNbr) = RandomPos(1:3) + END IF + END DO ! nPart + END DO ! k + END DO ! l + END DO ! m + + CASE(3) ! 3D + CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') + END SELECT + END DO ! iElem = 1, nElems END SUBROUTINE SetPartPosAndVeloEmissionDistribution diff --git a/src/particles/particle_tools.f90 b/src/particles/particle_tools.f90 index fabea3a78..4dccd105e 100644 --- a/src/particles/particle_tools.f90 +++ b/src/particles/particle_tools.f90 @@ -1159,7 +1159,7 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(iSpec,iInit,Pos,dimLower,dimUpp !USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistribution !< data in 2D cylindrical coordinates USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDelta USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMin -USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionN +USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionMax,EmissionDistributionNum ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- @@ -1199,13 +1199,13 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(iSpec,iInit,Pos,dimLower,dimUpp InterpolateEmissionDistribution2D = 0. ELSE ! 1.1 - idx1 = (iPos-1)*EmissionDistributionN(1) + jPos + idx1 = (iPos-1)*EmissionDistributionNum(1) + jPos ! 2.1 - idx2 = (iPos-1)*EmissionDistributionN(1) + jPos + 1 + idx2 = (iPos-1)*EmissionDistributionNum(1) + jPos + 1 ! 1.2 - idx3 = iPos*EmissionDistributionN(1) + jPos + idx3 = iPos*EmissionDistributionNum(1) + jPos ! 2.2 - idx4 = iPos*EmissionDistributionN(1) + jPos + 1 + idx4 = iPos*EmissionDistributionNum(1) + jPos + 1 ! Interpolate delta = EmissionDistributionDelta(1)*EmissionDistributionDelta(2) diff --git a/src/particles/pic/deposition/pic_depo.f90 b/src/particles/pic/deposition/pic_depo.f90 index 17b1bac8c..430b4d74c 100644 --- a/src/particles/pic/deposition/pic_depo.f90 +++ b/src/particles/pic/deposition/pic_depo.f90 @@ -595,10 +595,8 @@ SUBROUTINE InitShapeFunctionAdaptive() WRITE(UNIT=hilf3,FMT='(G0)') SFAdaptiveDOFDefault SFAdaptiveDOF = GETREAL('PIC-shapefunction-adaptive-DOF',TRIM(hilf3)) -IF(SFAdaptiveDOF.GT.DOFMax)THEN SWRITE(UNIT_StdOut,'(A,F10.2)') " PIC-shapefunction-adaptive-DOF =", SFAdaptiveDOF SWRITE(UNIT_StdOut,'(A,A19,A,F10.2)') " Maximum allowed is ",TRIM(hilf2)," =", DOFMax - SWRITE(UNIT_StdOut,*) "Reduce the number of DOF/SF in order to have no DOF outside of the deposition range (neighbour elems)" SWRITE(UNIT_StdOut,*) "Set a value lower or equal to than the maximum for a given polynomial degree N\n" SWRITE(UNIT_StdOut,*) " N: 1 2 3 4 5 6 7" SWRITE(UNIT_StdOut,*) " ----------------------------------------------------------------" @@ -606,6 +604,8 @@ SUBROUTINE InitShapeFunctionAdaptive() SWRITE(UNIT_StdOut,*) " Max. DOF | 2D: 12 28 50 78 113 153 201" SWRITE(UNIT_StdOut,*) " | 3D: 33 113 268 523 904 1436 2144" SWRITE(UNIT_StdOut,*) " ----------------------------------------------------------------" +IF(SFAdaptiveDOF.GT.DOFMax)THEN + SWRITE(UNIT_StdOut,*) "Reduce the number of DOF/SF in order to have no DOF outside of the deposition range (neighbour elems)" CALL abort(__STAMP__,'PIC-shapefunction-adaptive-DOF > '//TRIM(hilf2)//' is not allowed') ELSE ! Check which shape function dimension is used From 3c3e249c18009a446abf51b6af6b1e70d92a0cbd Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 26 Oct 2022 13:52:36 +0200 Subject: [PATCH 10/36] When using CalcPointsPerWavelength=T and not ini exact function uses the wavelength read-ini parameter, read the parameter here and use it for the calculation of the PPW criterion in each cell. --- src/analyze/analyze.f90 | 1 + src/equations/maxwell/equation.f90 | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/analyze/analyze.f90 b/src/analyze/analyze.f90 index 0dd2a2ac9..e67cf8e02 100644 --- a/src/analyze/analyze.f90 +++ b/src/analyze/analyze.f90 @@ -296,6 +296,7 @@ SUBROUTINE InitAnalyze() ! Points Per Wavelength CalcPointsPerWavelength = GETLOGICAL('CalcPointsPerWavelength') IF(CalcPointsPerWavelength)THEN + IF(WaveLength.LT.0.) WaveLength = GETREAL('WaveLength','1.') ! calculate cell local number excluding neighbor DOFs ALLOCATE( PPWCell(1:PP_nElems) ) PPWCell=0.0 diff --git a/src/equations/maxwell/equation.f90 b/src/equations/maxwell/equation.f90 index d979ae582..88729d5c6 100644 --- a/src/equations/maxwell/equation.f90 +++ b/src/equations/maxwell/equation.f90 @@ -209,6 +209,9 @@ SUBROUTINE InitEquation() c_corr_c2 = c_corr*c2 eta_c = (c_corr-1.)*c +! default +WaveLength = -1. + ! Read in boundary parameters IniExactFunc = GETINT('IniExactFunc') nRefStates=nBCs+1 From b239a3adc47e58928d7c70b784459b66f188a9ff Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 26 Oct 2022 20:13:17 +0200 Subject: [PATCH 11/36] Re-written emission distribution algorithm to automatically adapt the polynomial degree if the average number of emitted particles per sub volume falls below 1.0; estimate a polynomial degree >= PP_N that results in 1 particle per sub volume or emit the particle(s) in the element using the bounding box (cut-off of particles outside of the element via ARM). --- .../particle_position_and_velocity.f90 | 267 +++++++++++++----- 1 file changed, 204 insertions(+), 63 deletions(-) diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index 3cc67a0ba..26d2e621f 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -400,7 +400,7 @@ SUBROUTINE SetParticleVelocity(FractNbr,iInit,NbrOfParticle) END DO CASE('maxwell_lpn','2D_landmark','2D_landmark_copy','2D_landmark_neutralization') ! maxwell_lpn: Maxwell low particle number - ! 2D_landmark: Ionization profile from T. Charoy, 2D axial-azimuthal particle-in-cell benchmark for low-temperature partially + ! 2D_landmark: Ionization profile from T. Charoy, 2D axial-azimuthal particle-in-cell benchmark for low-temperature partially ! magnetized plasmas (2019) DO i = 1,NbrOfParticle PositionNbr = PDM%nextFreePosition(i+PDM%CurrentNextFreePosition) @@ -486,7 +486,7 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) USE MOD_Globals ,ONLY: myrank,UNIT_StdOut,MPI_COMM_WORLD,abort USE MOD_part_tools ,ONLY: InitializeParticleMaxwell,InterpolateEmissionDistribution2D USE MOD_Mesh_Vars ,ONLY: nElems,offsetElem -USE MOD_Particle_Vars ,ONLY: Species, PDM, PartState +USE MOD_Particle_Vars ,ONLY: Species, PDM, PartState, PEM, LastPartPos USE MOD_Particle_Tracking ,ONLY: ParticleInsideCheck USE MOD_Mesh_Tools ,ONLY: GetCNElemID USE MOD_Particle_Emission_Vars ,ONLY: EmissionDistributionDim, EmissionDistributionN @@ -498,6 +498,10 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) USE MOD_Interpolation_Vars ,ONLY: NodeTypeVISU,NodeType USE MOD_Eval_xyz ,ONLY: TensorProductInterpolation USE MOD_Mesh_Vars ,ONLY: NGeo,XCL_NGeo,XiCL_NGeo,wBaryCL_NGeo,offsetElem +USE MOD_Particle_Mesh_Vars ,ONLY: ElemVolume_Shared,BoundsOfElem_Shared +USE MOD_Mesh_Tools ,ONLY: GetCNElemID +USE MOD_Particle_Tracking_Vars ,ONLY: TrackingMethod +USE MOD_Dielectric_Vars ,ONLY: DoDielectric,isDielectricElem,DielectricNoParticles !---------------------------------------------------------------------------------------------------------------------------------- ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE @@ -509,95 +513,232 @@ SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) INTEGER,INTENT(OUT) :: NbrOfParticle !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -INTEGER :: iElem,iPart,nPart,GlobalElemID,PositionNbr +INTEGER :: iElem,iPart,GlobalElemID,PositionNbr REAL :: iRan, RandomPos(3), MPF REAL :: PartDens(1:3) ! dummy vector because the routine can only return vector values LOGICAL :: InsideFlag -INTEGER :: k,l,m -REAL :: densityVISU(1,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) -REAL :: J_NAnalyze(1,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) REAL :: IntegrationWeight -REAL :: Coords_NAnalyze(3,0:EmissionDistributionN,0:EmissionDistributionN,0:EmissionDistributionN) -REAL :: xIP_VISU(0:EmissionDistributionN),wIP_VISU(0:EmissionDistributionN) +INTEGER :: k,l,m REAL :: RandVal(3),Xi(3) -REAL :: Vdm_N_EQ_emission(0:EmissionDistributionN,0:EmissionDistributionN) ! < Vandermonde mapping from NodeType to equidistant (visu) node set +INTEGER :: nPart,Nloc,Nred +REAL :: nPartCell,nPartPerSubVol +REAL :: BBoxVolume,SimPartDens + +TYPE Interpolation + REAL,ALLOCATABLE :: densityVISU(:,:,:,:) + REAL,ALLOCATABLE :: J_NAnalyze(:,:,:,:) + REAL,ALLOCATABLE :: Coords_NAnalyze(:,:,:,:) + REAL,ALLOCATABLE :: xIP_VISU(:),wIP_VISU(:) + REAL,ALLOCATABLE :: Vdm_N_EQ_emission(:,:) ! < Vandermonde mapping from NodeType to equidistant (visu) node set +END TYPE Interpolation + +TYPE(Interpolation),ALLOCATABLE :: NED(:) !===================================================================================================================================/ - -! Allocate and determine Vandermonde mapping from NodeType to equidistant (visu) node set -CALL GetVandermonde(PP_N, NodeType, EmissionDistributionN, NodeTypeVISU, Vdm_N_EQ_emission, modal=.FALSE.) -CALL GetNodesAndWeights(EmissionDistributionN, NodeTypeVISU, xIP_VISU, wIP=wIP_VISU) +! Sanity check +IF(PP_N.GT.EmissionDistributionN) CALL abort(__STAMP__,'PP_N > EmissionDistributionN') + +! Allocate type for all polynomial degrees from PP_N to EmissionDistributionN +ALLOCATE(NED(PP_N:EmissionDistributionN)) + +DO Nloc = PP_N, EmissionDistributionN + ! Allocate all arrays for Nloc + ALLOCATE(NED(Nloc)%densityVISU(1,0:Nloc,0:Nloc,0:Nloc)) + ALLOCATE(NED(Nloc)%J_NAnalyze(1,0:Nloc,0:Nloc,0:Nloc)) + ALLOCATE(NED(Nloc)%Coords_NAnalyze(3,0:Nloc,0:Nloc,0:Nloc)) + ALLOCATE(NED(Nloc)%xIP_VISU(0:Nloc)) + ALLOCATE(NED(Nloc)%wIP_VISU(0:Nloc)) + ALLOCATE(NED(Nloc)%Vdm_N_EQ_emission(0:Nloc,0:Nloc)) + + ! Allocate and determine Vandermonde mapping from NodeType to equidistant (visu) node set + CALL GetVandermonde(PP_N, NodeType, Nloc, NodeTypeVISU, NED(Nloc)%Vdm_N_EQ_emission, modal=.FALSE.) + CALL GetNodesAndWeights(Nloc, NodeTypeVISU, NED(Nloc)%xIP_VISU, wIP=NED(Nloc)%wIP_VISU) +END DO ! Nloc = 1, EmissionDistributionN NbrOfParticle = 0 MPF = Species(iSpec)%MacroParticleFactor DO iElem = 1, nElems + ! Do not emit particles in dielectrics + IF(DoDielectric)THEN + IF(DielectricNoParticles.AND.isDielectricElem(iElem)) CYCLE + END IF ! DoDielectric + GlobalElemID = iElem + offsetElem + SELECT CASE(EmissionDistributionDim) CASE(1) ! 1D CALL abort(__STAMP__,'EmissionDistributionDim=1 is not implemented') CASE(2) ! 2D ! Interpolate the physical position Elem_xGP to the analyze position, needed for exact function - CALL ChangeBasis3D(3,PP_N,EmissionDistributionN,Vdm_N_EQ_emission,Elem_xGP(1:3,:,:,:,iElem),Coords_NAnalyze(1:3,:,:,:)) - - densityVISU = -1. - DO m=0,EmissionDistributionN - DO l=0,EmissionDistributionN - DO k=0,EmissionDistributionN - ! Density field from .h5 data that is interpolated to the equidistant interpolation points (bilinear interpolation) - PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,Coords_NAnalyze(1:3,k,l,m),dimLower=3,dimUpper=3,& - transformation=.FALSE.) - densityVISU(1,k,l,m) = PartDens(1) - END DO ! k - END DO ! l - END DO ! m + CALL ChangeBasis3D(3, PP_N, EmissionDistributionN, NED(EmissionDistributionN)%Vdm_N_EQ_emission, Elem_xGP(1:3,:,:,:,iElem), & + NED(EmissionDistributionN)%Coords_NAnalyze(1:3,:,:,:)) ! Interpolate the Jacobian to the equidistant grid: be careful we interpolate the inverse of the inverse of the jacobian ;-) - CALL ChangeBasis3D(1, PP_N, EmissionDistributionN, Vdm_N_EQ_emission, 1./sJ(:,:,:,iElem), J_NAnalyze(1:1,:,:,:)) + CALL ChangeBasis3D(1, PP_N, EmissionDistributionN, NED(EmissionDistributionN)%Vdm_N_EQ_emission, 1./sJ(:,:,:,iElem), & + NED(EmissionDistributionN)%J_NAnalyze(1:1,:,:,:)) - ! Loop over all interpolation points + ! Integrate the density with the highest polynomial degree and calculate the average number of particles for the whole cell + nPartCell = 0. + NED(EmissionDistributionN)%densityVISU = -1. DO m=0,EmissionDistributionN DO l=0,EmissionDistributionN DO k=0,EmissionDistributionN - IntegrationWeight = wIP_VISU(k)*wIP_VISU(l)*wIP_VISU(m)*J_NAnalyze(1,k,l,m) - - ! Add noise via random number - CALL RANDOM_NUMBER(iRan) - nPart = INT(densityVISU(1,k,l,m)*IntegrationWeight/MPF + iRan) - - ! Loop over all newly created particles - DO iPart = 1, nPart - CALL RANDOM_NUMBER(RandVal) - Xi(1) = -1.0 + SUM(wIP_VISU(0:k-1)) + wIP_VISU(k) * RandVal(1) - Xi(2) = -1.0 + SUM(wIP_VISU(0:l-1)) + wIP_VISU(l) * RandVal(2) - Xi(3) = -1.0 + SUM(wIP_VISU(0:m-1)) + wIP_VISU(m) * RandVal(3) - IF(ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0))THEN - IPWRITE(UNIT_StdOut,*) "Xi =", Xi - CALL abort(__STAMP__,'xi out of range') - END IF ! ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0) - ! Get the physical coordinates that correspond to the reference coordinates - CALL TensorProductInterpolation(Xi(1:3),3,NGeo,XiCL_NGeo,wBaryCL_NGeo,XCL_NGeo(1:3,0:NGeo,0:NGeo,0:NGeo,iElem),& - RandomPos(1:3)) !Map into phys. space - - !InsideFlag = .FALSE. - !InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) - InsideFlag = .TRUE. - - ! Exclude particles outside of the element - IF (InsideFlag) THEN - NbrOfParticle = NbrOfParticle + 1 - PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) - IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& - (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) - PartState(1:3,PositionNbr) = RandomPos(1:3) ! Little hack: store new particle position temporarily in PartState - CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) - PartState(1:3,PositionNbr) = RandomPos(1:3) - END IF - END DO ! nPart + ! Evaluate the equidistant solution from .h5 data file + PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec, iInit, NED(EmissionDistributionN)%Coords_NAnalyze(1:3,k,l,m),& + dimLower=3, dimUpper=3, transformation=.FALSE.) + + ! Get density at interpolation point + NED(EmissionDistributionN)%densityVISU(1,k,l,m) = PartDens(1) + + ! Integrate the Jacobian + IntegrationWeight = NED(EmissionDistributionN)%wIP_VISU(k)*& + NED(EmissionDistributionN)%wIP_VISU(l)*& + NED(EmissionDistributionN)%wIP_VISU(m)*& + NED(EmissionDistributionN)%J_NAnalyze(1,k,l,m) + + ! Get total number of particles per cell + nPartCell = nPartCell + NED(EmissionDistributionN)%densityVISU(1,k,l,m)*IntegrationWeight END DO ! k END DO ! l END DO ! m + ! Apply MPF after summation + nPartCell = nPartCell/REAL(MPF) + + ! Skip empty elements: Cut-off at arbitrarily small number + IF(nPartCell.LT.1e-4) CYCLE + + ! Get number of particles per sub volume + nPartPerSubVol = nPartCell/REAL((EmissionDistributionN+1)**3) + + ! Check if number of particles per sub cell drops below 1 (this would cause artificial noise in the density distribution) + IF(nPartPerSubVol.LT.1.0)THEN + ! Approximation of polynomial degree for 1 particle per sub volume, use lower value INT() to increase the number of particles + Nred = INT(nPartCell**(1./3.) - 1.0) + ELSE + ! Use full emission polynomial + Nred = EmissionDistributionN + END IF + + ! If less than 1 particle per element is emitted, force ARM emission + IF(nPartCell.LT.1.0) Nred = 0 + + ! Check if the emission polynomial degree has to be reduced and if it falls below PP_N use cell-const. emission (via ARM) + IF(Nred.GE.PP_N)THEN + ! Emit all particles in the sub volumes + + ! Check if already calculated + IF(Nred.NE.EmissionDistributionN)THEN + ! Interpolate the physical position Elem_xGP to the analyze position, needed for exact function + CALL ChangeBasis3D(3, PP_N, Nred, NED(Nred)%Vdm_N_EQ_emission, Elem_xGP(1:3,:,:,:,iElem), NED(Nred)%Coords_NAnalyze(1:3,:,:,:)) + + ! Interpolate the Jacobian to the equidistant grid: be careful we interpolate the inverse of the inverse of the jacobian ;-) + CALL ChangeBasis3D(1, PP_N, Nred, NED(Nred)%Vdm_N_EQ_emission, 1./sJ(:,:,:,iElem), NED(Nred)%J_NAnalyze(1:1,:,:,:)) + END IF ! Nred.NE.EmissionDistributionN + + ! Loop over all interpolation points + NED(Nred)%densityVISU = -1. + DO m=0,Nred + DO l=0,Nred + DO k=0,Nred + ! Density field from .h5 data that is interpolated to the equidistant interpolation points (bilinear interpolation) + PartDens(1:3) = InterpolateEmissionDistribution2D(iSpec,iInit,NED(Nred)%Coords_NAnalyze(1:3,k,l,m),dimLower=3,dimUpper=3,& + transformation=.FALSE.) + NED(Nred)%densityVISU(1,k,l,m) = PartDens(1) + + ! Integrate the Jacobian + IntegrationWeight = NED(Nred)%wIP_VISU(k)*NED(Nred)%wIP_VISU(l)*NED(Nred)%wIP_VISU(m)*NED(Nred)%J_NAnalyze(1,k,l,m) + + ! Add noise via random number + CALL RANDOM_NUMBER(iRan) + nPart = INT(NED(Nred)%densityVISU(1,k,l,m)*IntegrationWeight/MPF + iRan) + + ! Loop over all newly created particles + DO iPart = 1, nPart + CALL RANDOM_NUMBER(RandVal) + Xi(1) = -1.0 + SUM(NED(Nred)%wIP_VISU(0:k-1)) + NED(Nred)%wIP_VISU(k) * RandVal(1) + Xi(2) = -1.0 + SUM(NED(Nred)%wIP_VISU(0:l-1)) + NED(Nred)%wIP_VISU(l) * RandVal(2) + Xi(3) = -1.0 + SUM(NED(Nred)%wIP_VISU(0:m-1)) + NED(Nred)%wIP_VISU(m) * RandVal(3) + IF(ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0))THEN + IPWRITE(UNIT_StdOut,*) "Xi =", Xi + CALL abort(__STAMP__,'xi out of range') + END IF ! ANY(Xi.GT.1.0).OR.ANY(Xi.LT.-1.0) + ! Get the physical coordinates that correspond to the reference coordinates + CALL TensorProductInterpolation(Xi(1:3),3,NGeo,XiCL_NGeo,wBaryCL_NGeo,XCL_NGeo(1:3,0:NGeo,0:NGeo,0:NGeo,iElem),& + RandomPos(1:3)) !Map into phys. space + + !InsideFlag = .FALSE. + !InsideFlag = ParticleInsideCheck(RandomPos,iPart,GlobalElemID) + InsideFlag = .TRUE. + + ! Exclude particles outside of the element + IF (InsideFlag) THEN + NbrOfParticle = NbrOfParticle + 1 + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) + PEM%GlobalElemID(PositionNbr) = GlobalElemID + PDM%ParticleInside(PositionNbr) = .TRUE. + IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& + (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + PartState(1:3,PositionNbr) = RandomPos(1:3) + CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) + END IF + END DO ! nPart + END DO ! k + END DO ! l + END DO ! m + + ELSE ! Nred < PP_N + ! Emit all particles in the element (ARM) + ASSOCIATE( Bounds => BoundsOfElem_Shared(1:2,1:3,GlobalElemID) ) ! 1-2: Min, Max value; 1-3: x,y,z + + ! nPartCell is the REAL number of particles for the element with the correct volume of the element + ! get number of particles for BB volume (outside particles are removed via ARM) + BBoxVolume = (Bounds(2,3) - Bounds(1,3))*(Bounds(2,2) - Bounds(1,2))*(Bounds(2,1) - Bounds(1,1)) + ! Reconstruct density of simulation particles (without considering MPF) + SimPartDens = nPartCell/ElemVolume_Shared(GetCNElemID(GlobalElemID)) + CALL RANDOM_NUMBER(iRan) + nPart = INT(SimPartDens * BBoxVolume + iRan) + !nPart=0 + + DO iPart = 1, nPart + InsideFlag = .FALSE. ! default + + ! Get random position in bounding box + CALL RANDOM_NUMBER(RandomPos) + RandomPos(1:3) = Bounds(1,1:3) + RandomPos(1:3)*(Bounds(2,1:3)-Bounds(1,1:3)) + + ! Check if particle is inside the element (refmapping and tracing require a virtual particle with correct properties) + SELECT CASE(TrackingMethod) + CASE(REFMAPPING,TRACING) + ! Attention: NbrOfParticle+PDM%CurrentNextFreePosition + 1 + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition + 1) + PEM%GlobalElemID(PositionNbr) = GlobalElemID + LastPartPos(1:3,PositionNbr) = RandomPos(1:3) + InsideFlag = ParticleInsideCheck(RandomPos,PositionNbr,GlobalElemID) + CASE(TRIATRACKING) + InsideFlag = ParticleInsideCheck(RandomPos,-1,GlobalElemID) + CASE DEFAULT + CALL abort(__STAMP__,'TrackingMethod not implemented! TrackingMethod =',IntInfoOpt=TrackingMethod) + END SELECT + + ! Exclude particles outside of the element + IF (InsideFlag) THEN + NbrOfParticle = NbrOfParticle + 1 + PositionNbr = PDM%nextFreePosition(NbrOfParticle+PDM%CurrentNextFreePosition) + PEM%GlobalElemID(PositionNbr) = GlobalElemID + PDM%ParticleInside(PositionNbr) = .TRUE. + IF((PositionNbr.GE.PDM%maxParticleNumber).OR.& + (PositionNbr.EQ.0)) CALL abort(__STAMP__,'Emission: Increase maxParticleNumber!',PositionNbr) + PartState(1:3,PositionNbr) = RandomPos(1:3) + CALL InitializeParticleMaxwell(PositionNbr,iSpec,iElem,Mode=2,iInit=iInit) + END IF + END DO ! nPart + + END ASSOCIATE + + END IF ! Nred.GE.PP_N + CASE(3) ! 3D CALL abort(__STAMP__,'EmissionDistributionDim=3 is not implemented') END SELECT From 9d38e3ddb4cfb0a0067a599eb1a72ebdbef6ca03 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 12 Nov 2022 20:57:33 +0100 Subject: [PATCH 12/36] Allow calculation of PPW for input wavelength also for non-Maxwell solvers. --- .../parameter.ini | 2 +- src/analyze/analyze.f90 | 18 ++++-------------- src/equations/poisson/equation_vars.f90 | 1 + 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini index d5ea88999..582e83821 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini @@ -68,7 +68,7 @@ PIC-shapefunction-alpha = 4 Part-FIBGMdeltas = (/0.5,0.001,.5/) -Part-FileNameEmissionDistribution = reggie-linear-rot-symmetry-species-init.h5 +Part-EmissionDistributionFileName = reggie-linear-rot-symmetry-species-init.h5 ! =============================================================================== ! ! Species1 - electrons diff --git a/src/analyze/analyze.f90 b/src/analyze/analyze.f90 index 8440ef43c..70bf87b72 100644 --- a/src/analyze/analyze.f90 +++ b/src/analyze/analyze.f90 @@ -166,9 +166,7 @@ SUBROUTINE InitAnalyze() USE MOD_TimeAverage_Vars ,ONLY: doCalcTimeAverage USE MOD_TimeAverage ,ONLY: InitTimeAverage USE MOD_TimeDisc_Vars ,ONLY: TEnd -#ifdef maxwell USE MOD_Equation_vars ,ONLY: Wavelength -#endif /* maxwell */ USE MOD_Particle_Mesh_Vars ,ONLY: ElemCharLength_Shared #if USE_MPI && defined(PARTICLES) USE MOD_Mesh_Vars ,ONLY: offSetElem @@ -296,17 +294,13 @@ SUBROUTINE InitAnalyze() ! Points Per Wavelength CalcPointsPerWavelength = GETLOGICAL('CalcPointsPerWavelength') IF(CalcPointsPerWavelength)THEN - IF(WaveLength.LT.0.) WaveLength = GETREAL('WaveLength','1.') ! calculate cell local number excluding neighbor DOFs ALLOCATE( PPWCell(1:PP_nElems) ) PPWCell=0.0 CALL AddToElemData(ElementOut,'PPWCell',RealArray=PPWCell(1:PP_nElems)) ! Calculate PPW for each cell -#ifdef maxwell + IF(WaveLength.LT.0.) WaveLength = GETREAL('WaveLength','1.') CALL PrintOption('Wavelength for PPWCell','OUTPUT',RealOpt=Wavelength) -#else - CALL PrintOption('Wavelength for PPWCell (fixed to 1.0)','OUTPUT',RealOpt=1.0) -#endif /* maxwell */ PPWCellMin=HUGE(1.) PPWCellMax=-HUGE(1.) DO iElem = 1, nElems @@ -316,13 +310,9 @@ SUBROUTINE InitAnalyze() #else CNElemID = iElem #endif /*USE_MPI && defined(PARTICLES)*/ -#ifdef maxwell - PPWCell(iElem) = (REAL(PP_N)+1.)*Wavelength/ElemCharLength_Shared(CNElemID) -#else - PPWCell(iElem) = (REAL(PP_N)+1.)/ElemCharLength_Shared(CNElemID) -#endif /* maxwell */ - PPWCellMin=MIN(PPWCellMin,PPWCell(iElem)) - PPWCellMax=MAX(PPWCellMax,PPWCell(iElem)) + PPWCell(iElem) = (REAL(PP_N)+1.)*Wavelength/ElemCharLength_Shared(CNElemID) + PPWCellMin = MIN(PPWCellMin,PPWCell(iElem)) + PPWCellMax = MAX(PPWCellMax,PPWCell(iElem)) END DO ! iElem = 1, nElems #if USE_MPI IF(MPIroot)THEN diff --git a/src/equations/poisson/equation_vars.f90 b/src/equations/poisson/equation_vars.f90 index 4ebfeda90..99a141f99 100644 --- a/src/equations/poisson/equation_vars.f90 +++ b/src/equations/poisson/equation_vars.f90 @@ -27,6 +27,7 @@ MODULE MOD_Equation_Vars REAL :: IniCenter(3) REAL :: IniAmplitude REAL :: IniHalfwidth +REAL :: WaveLength !> wave length ! needed for various stuff (compilation) REAL :: c_corr From c42eb14f9911a0d734495070b56c8e5758814c11 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 12 Nov 2022 23:51:05 +0100 Subject: [PATCH 13/36] Limit width of parameter value output to 50 characters to prevent large vectors from creating huge output widths. --- src/readintools/readintools.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/readintools/readintools.f90 b/src/readintools/readintools.f90 index 599d193db..7f16b8f45 100644 --- a/src/readintools/readintools.f90 +++ b/src/readintools/readintools.f90 @@ -873,6 +873,7 @@ SUBROUTINE read_options(this, filename, furtherini) DO WHILE (associated(current)) this%maxNameLen = MAX(this%maxNameLen, current%opt%GETNAMELEN()) this%maxValueLen = MAX(this%maxValueLen, current%opt%GETVALUELEN()) + this%maxValueLen = MIN(this%maxValueLen, 50) current => current%next END DO From ec7823cf176666c548b8bdb180996f6f1c02b50e Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 12 Nov 2022 23:52:14 +0100 Subject: [PATCH 14/36] Output interface index when Riemann select case aborts. --- src/equations/maxwell/riemann.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/equations/maxwell/riemann.f90 b/src/equations/maxwell/riemann.f90 index 4a9789a92..b89bcde38 100644 --- a/src/equations/maxwell/riemann.f90 +++ b/src/equations/maxwell/riemann.f90 @@ -124,7 +124,7 @@ SUBROUTINE Riemann(Flux_Master,Flux_Slave,U_Master,U_Slave,NormVec,SideID) CASE DEFAULT CALL abort(& __STAMP__& - ,'Unknown interface type for Riemann solver (vacuum, dielectric, PML ...)') + ,'Unknown interface type for Riemann solver (vacuum, dielectric, PML ...)',IntInfoOpt=InterfaceRiemann(SideID)) END SELECT END SUBROUTINE Riemann From de1ba9308190cb0f7e156d8d0ff7b94462eecc94 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sun, 13 Nov 2022 22:12:55 +0100 Subject: [PATCH 15/36] Fixed sanity check for interface detection and subsequent Riemann flux assignment. Currency, Mortar interfaces between vacuum <-> dielectric regions are not implemented. --- src/equations/maxwell/riemann.f90 | 8 +++---- src/interfaces/interfaces.f90 | 40 +++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/equations/maxwell/riemann.f90 b/src/equations/maxwell/riemann.f90 index b89bcde38..a20811692 100644 --- a/src/equations/maxwell/riemann.f90 +++ b/src/equations/maxwell/riemann.f90 @@ -66,7 +66,7 @@ SUBROUTINE Riemann(Flux_Master,Flux_Slave,U_Master,U_Slave,NormVec,SideID) ! MODULES USE MOD_PreProc USE MOD_Dielectric_vars ,ONLY: Dielectric_Master -USE MOD_Globals ,ONLY: Abort +USE MOD_Globals ,ONLY: abort,myrank,UNIT_StdOut USE MOD_PML_vars ,ONLY: PMLnVar USE MOD_Interfaces_Vars ,ONLY: InterfaceRiemann ! IMPLICIT VARIABLE HANDLING @@ -122,9 +122,9 @@ SUBROUTINE Riemann(Flux_Master,Flux_Slave,U_Master,U_Slave,NormVec,SideID) ! 2.) vacuum master side CALL RiemannVacuum(Flux_Master(1:8,:,:),U_Master( :,:,:),U_Slave( :,:,:),NormVec(:,:,:)) CASE DEFAULT - CALL abort(& - __STAMP__& - ,'Unknown interface type for Riemann solver (vacuum, dielectric, PML ...)',IntInfoOpt=InterfaceRiemann(SideID)) + IPWRITE(UNIT_StdOut,*) "SideID = ", SideID + IPWRITE(UNIT_StdOut,*) "InterfaceRiemann(SideID) = ", InterfaceRiemann(SideID) + CALL abort(__STAMP__,'Unknown interface type for Riemann solver (vacuum, dielectric, PML ...)') END SELECT END SUBROUTINE Riemann diff --git a/src/interfaces/interfaces.f90 b/src/interfaces/interfaces.f90 index a4bb4e2d3..868e33f6d 100644 --- a/src/interfaces/interfaces.f90 +++ b/src/interfaces/interfaces.f90 @@ -74,7 +74,8 @@ SUBROUTINE InitInterfaces !> - vacuum -> dielectri : RIEMANN_VAC2DIELECTRIC_NC = 6 ! for non-conservative fluxes (two fluxes) !=================================================================================================================================== ! MODULES -USE MOD_Mesh_Vars ,ONLY: nSides +USE MOD_globals +USE MOD_Mesh_Vars ,ONLY: nSides,Face_xGP,NGeo,MortarType #if ! (USE_HDG) USE MOD_PML_vars ,ONLY: DoPML,isPMLFace #endif /*NOT HDG*/ @@ -102,15 +103,12 @@ SUBROUTINE InitInterfaces LBWRITE(UNIT_stdOut,'(A)') ' INIT INTERFACES...' ALLOCATE(InterfaceRiemann(1:nSides)) DO SideID=1,nSides - InterfaceRiemann(SideID)=-1 ! set default to invalid number: check later + InterfaceRiemann(SideID)=-2 ! set default to invalid number: check later ! 0.) Sanity: It is forbidden to connect a PML to a dielectric region because it is not implemented! #if !(USE_HDG) /*pure Maxwell simulations*/ IF(DoPML.AND.DoDielectric)THEN - IF(isPMLFace(SideID).AND.isDielectricFace(SideID))THEN - CALL abort(& - __STAMP__& - ,'It is forbidden to connect a PML to a dielectric region! (Not implemented)') - END IF + IF(isPMLFace(SideID).AND.isDielectricFace(SideID)) CALL abort(__STAMP__,& + 'It is forbidden to connect a PML to a dielectric region! (Not implemented)') END IF ! 1.) Check Perfectly Matched Layer @@ -135,7 +133,11 @@ SUBROUTINE InitInterfaces IF(isDielectricInterFace(SideID))THEN ! a) physical <-> dielectric region: for Riemann solver, select A+ and A- as functions of f(Eps0,Mu0) or f(EpsR,MuR) ElemID = SideToElem(S2E_ELEM_ID,SideID) ! get master element ID for checking if it is in a physical or dielectric region - IF(ElemID.EQ.-1) CYCLE ! skip + IF(MortarType(1,SideID).GE.0) CALL abort(__STAMP__,'Mortars not fully implemented for dielectric <-> vacuum interfaces') + IF(ElemID.EQ.-1) THEN + InterfaceRiemann(SideID)=-1 + CYCLE ! skip + END IF IF(isDielectricElem(ElemID))THEN ! a1) master is DIELECTRIC and slave PHYSICAL IF(DielectricFluxNonConserving)THEN ! use one flux (conserving) or two fluxes (non-conserving) at the interface @@ -163,11 +165,25 @@ SUBROUTINE InitInterfaces ! d) no Dielectric, standard flux InterfaceRiemann(SideID)=RIEMANN_VACUUM END IF ! DoDielectric +END DO ! SideID + - IF(InterfaceRiemann(SideID).EQ.-1)THEN ! check if the default value remains unchanged - CALL abort(& - __STAMP__& - ,'Interface for Riemann solver not correctly determined (vacuum, dielectric, PML ...)') +! Check if all sides have correctly been set +DO SideID=1,nSides + IF(InterfaceRiemann(SideID).EQ.-2)THEN ! check if the default value remains unchanged +#if !(USE_HDG) /*pure Maxwell simulations*/ + IPWRITE(UNIT_StdOut,*) "DoPML = ", DoPML +#endif /*NOT HDG*/ + IPWRITE(UNIT_StdOut,*) "DoDielectric = ", DoDielectric + IPWRITE(UNIT_StdOut,*) "SideID = ", SideID + IPWRITE(UNIT_StdOut,*) "MortarType(1,SideID) = ", MortarType(1,SideID) + IPWRITE(UNIT_StdOut,*) "InterfaceRiemann(SideID) = ", InterfaceRiemann(SideID) + IPWRITE(UNIT_StdOut,*) "SideToElem(S2E_ELEM_ID,SideID) = ", SideToElem(S2E_ELEM_ID,SideID) + IPWRITE(UNIT_StdOut,*) "Face_xGP(1:3,0,0,SideID) = ", Face_xGP(1:3,0,0,SideID) + IPWRITE(UNIT_StdOut,*) "Face_xGP(1:3 , 0 , NGeo , SideID) =" , Face_xGP(1:3 , 0 , NGeo , SideID) + IPWRITE(UNIT_StdOut,*) "Face_xGP(1:3 , NGeo , 0 , SideID) =" , Face_xGP(1:3 , NGeo , 0 , SideID) + IPWRITE(UNIT_StdOut,*) "Face_xGP(1:3 , NGeo , NGeo , SideID) =" , Face_xGP(1:3 , NGeo , NGeo , SideID) + CALL abort(__STAMP__,'Interface for Riemann solver not correctly determined (vacuum, dielectric, PML)') END IF END DO ! SideID From 58cefdef3d5fecb0e9ef0ffe277ce82df0e7bce8 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 19 Nov 2022 22:04:44 +0100 Subject: [PATCH 16/36] Fixed iterator in time avg for Maxwell solver. --- src/equations/maxwell/timeavg.f90 | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/equations/maxwell/timeavg.f90 b/src/equations/maxwell/timeavg.f90 index b4c62561b..a75d3f42d 100644 --- a/src/equations/maxwell/timeavg.f90 +++ b/src/equations/maxwell/timeavg.f90 @@ -93,13 +93,13 @@ SUBROUTINE InitTimeAverage() DO iVar=1,PP_nVar VarNamesAvgList(iVar)=StrVarNames(iVar) END DO ! iVar=1,PP_nVar -VarNamesAvgList( 9)='ElectricFieldMagnitude' -VarNamesAvgList(10)='MagneticFieldMagnitude' +VarNamesAvgList(PP_nVar+1)='ElectricFieldMagnitude' +VarNamesAvgList(PP_nVar+2)='MagneticFieldMagnitude' ! derived quantity -VarNamesAvgList(11)='PoyntingVectorX' -VarNamesAvgList(12)='PoyntingVectorY' -VarNamesAvgList(13)='PoyntingVectorZ' -VarNamesAvgList(14)='PoyntingVectorMagnitude' +VarNamesAvgList(PP_nVar+3)='PoyntingVectorX' +VarNamesAvgList(PP_nVar+4)='PoyntingVectorY' +VarNamesAvgList(PP_nVar+5)='PoyntingVectorZ' +VarNamesAvgList(PP_nVar+6)='PoyntingVectorMagnitude' #ifdef PARTICLES iCounter=PP_nVar+6 @@ -129,16 +129,16 @@ SUBROUTINE InitTimeAverage() DO iVar=1,PP_nVar VarNamesFlucList(iVar)=StrVarNames(iVar) END DO ! iVar=1,PP_nVar -VarNamesFlucList( 9)='ElectricFieldMagnitude' -VarNamesFlucList(10)='MagneticFieldMagnitude' +VarNamesFlucList(PP_nVar+1)='ElectricFieldMagnitude' +VarNamesFlucList(PP_nVar+2)='MagneticFieldMagnitude' ! derived quantity -VarNamesFlucList(11)='PoyntingVectorX' -VarNamesFlucList(12)='PoyntingVectorY' -VarNamesFlucList(13)='PoyntingVectorZ' -VarNamesFlucList(14)='PoyntingVectorMagnitude' +VarNamesFlucList(PP_nVar+3)='PoyntingVectorX' +VarNamesFlucList(PP_nVar+4)='PoyntingVectorY' +VarNamesFlucList(PP_nVar+5)='PoyntingVectorZ' +VarNamesFlucList(PP_nVar+6)='PoyntingVectorMagnitude' #ifdef PARTICLES -iCounter=PP_nVar+2 +iCounter=PP_nVar+6 DO iSpec=1,nSpecies WRITE(strhelp,'(I2.2)') iSpec VarnamesFlucList(iCounter+1)=TRIM('PowerDensityX-Spec')//TRIM(strhelp) @@ -214,7 +214,7 @@ SUBROUTINE InitTimeAverage() ! particles, additional marking for sampling #ifdef PARTICLES -iCounter=PP_nVar+2 +iCounter=PP_nVar+6 ALLOCATE(DoPowerDensity(1:nSpecies)) DoPowerDensity=.FALSE. nSpecPowerDensity=0 From f1604bc2f6b1b3f619558f890520815727c335ff Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 19 Nov 2022 22:05:34 +0100 Subject: [PATCH 17/36] Added calculated of coupled power to LSERK Maxwell timedisc. --- src/particles/analyze/particle_analyze.f90 | 2 +- src/timedisc/timedisc_TimeStepByLSERK.f90 | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/particles/analyze/particle_analyze.f90 b/src/particles/analyze/particle_analyze.f90 index 8c6d3d780..df66e8917 100644 --- a/src/particles/analyze/particle_analyze.f90 +++ b/src/particles/analyze/particle_analyze.f90 @@ -570,7 +570,7 @@ SUBROUTINE InitParticleAnalyze() DisplayCoupledPower = GETLOGICAL('DisplayCoupledPower') DoPartAnalyze = .TRUE. PCouplAverage = 0.0 -#if !((PP_TimeDiscMethod==500) || (PP_TimeDiscMethod==501) || (PP_TimeDiscMethod==502) || (PP_TimeDiscMethod==506) || (PP_TimeDiscMethod==507) || (PP_TimeDiscMethod==508) || (PP_TimeDiscMethod==509)) +#if !((PP_TimeDiscMethod==1) || (PP_TimeDiscMethod==2) || (PP_TimeDiscMethod==6) || (PP_TimeDiscMethod==500) || (PP_TimeDiscMethod==501) || (PP_TimeDiscMethod==502) || (PP_TimeDiscMethod==506) || (PP_TimeDiscMethod==507) || (PP_TimeDiscMethod==508) || (PP_TimeDiscMethod==509)) CALL abort(__STAMP__,'ERROR: CalcCoupledPower is not implemented yet with the chosen time discretization method!') #endif ! Allocate type array for all ranks diff --git a/src/timedisc/timedisc_TimeStepByLSERK.f90 b/src/timedisc/timedisc_TimeStepByLSERK.f90 index 74f26fffa..019ccdeb1 100644 --- a/src/timedisc/timedisc_TimeStepByLSERK.f90 +++ b/src/timedisc/timedisc_TimeStepByLSERK.f90 @@ -53,6 +53,8 @@ SUBROUTINE TimeStepByLSERK() USE MOD_TimeDisc_Vars ,ONLY: Phit_temp #endif /*PP_POIS*/ #ifdef PARTICLES +USE MOD_Particle_Analyze_Tools ,ONLY: CalcCoupledPowerPart +USE MOD_Particle_Analyze_Vars ,ONLY: CalcCoupledPower,PCoupl USE MOD_Particle_Tracking ,ONLY: PerformTracking USE MOD_Particle_Tracking_vars ,ONLY: tTracking,tLocalization,MeasureTrackTime USE MOD_PICDepo ,ONLY: Deposition @@ -97,6 +99,9 @@ SUBROUTINE TimeStepByLSERK() ! RK coefficients b_dt = RK_b*dt +#if defined(PARTICLES) +IF (CalcCoupledPower) PCoupl = 0. ! if output of coupled power is active: reset PCoupl +#endif /*defined(PARTICLES)*/ DO iStage = 1,nRKStages IF (iStage.EQ.1) THEN tStage = time @@ -156,8 +161,10 @@ SUBROUTINE TimeStepByLSERK() PartState(1:3,iPart) = PartState(1:3,iPart) + PartState(4:6,iPart)*b_dt(iStage) ! Don't push the velocity component of neutral particles! IF (isPushParticle(iPart)) THEN + IF (CalcCoupledPower) CALL CalcCoupledPowerPart(iPart,'before') Pt_temp( 4:6,iPart) = Pt( 1:3,iPart) PartState(4:6,iPart) = PartState(4:6,iPart) + Pt(1:3,iPart)*b_dt(iStage) + IF (CalcCoupledPower) CALL CalcCoupledPowerPart(iPart,'after') END IF END IF ! PDM%ParticleInside(iPart) END DO ! iPart=1,PDM%ParticleVecLength @@ -168,8 +175,10 @@ SUBROUTINE TimeStepByLSERK() PartState(1:3,iPart) = PartState(1:3,iPart) + Pt_temp(1:3,iPart)*b_dt(iStage) ! Don't push the velocity component of neutral particles! IF (isPushParticle(iPart)) THEN + IF (CalcCoupledPower) CALL CalcCoupledPowerPart(iPart,'before') Pt_temp( 4:6,iPart) = Pt(1:3,iPart) - RK_a(iStage) * Pt_temp(4:6,iPart) PartState(4:6,iPart) = PartState(4:6,iPart) + Pt_temp(4:6,iPart)*b_dt(iStage) + IF (CalcCoupledPower) CALL CalcCoupledPowerPart(iPart,'after') END IF END IF ! PDM%ParticleInside(iPart) END DO ! iPart=1,PDM%ParticleVecLength From c242808e684665921d0d3d1ec311f50a6328f2ed Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sat, 19 Nov 2022 22:06:17 +0100 Subject: [PATCH 18/36] Fixes for TVib, TRot and Telec initialization when using SpaceIC 'EmissionDistribution'. --- src/particles/dsmc/dsmc_init.f90 | 9 +++++++-- src/timedisc/timedisc.f90 | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/particles/dsmc/dsmc_init.f90 b/src/particles/dsmc/dsmc_init.f90 index 54f5d94ab..bacf9d900 100644 --- a/src/particles/dsmc/dsmc_init.f90 +++ b/src/particles/dsmc/dsmc_init.f90 @@ -718,12 +718,17 @@ SUBROUTINE InitDSMC() DO iInit = 1, Species(iSpec)%NumberOfInits WRITE(UNIT=hilf2,FMT='(I0)') iInit hilf2=TRIM(hilf)//'-Init'//TRIM(hilf2) - IF((SpecDSMC(iSpec)%InterID.EQ.2).OR.(SpecDSMC(iSpec)%InterID.EQ.20)) THEN + IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN + SpecDSMC(iSpec)%Init(iInit)%TVib = GETREAL('Part-Species'//TRIM(hilf2)//'-TempVib','300.0') + SpecDSMC(iSpec)%Init(iInit)%TRot = GETREAL('Part-Species'//TRIM(hilf2)//'-TempRot','300.0') + ELSEIF((SpecDSMC(iSpec)%InterID.EQ.2).OR.(SpecDSMC(iSpec)%InterID.EQ.20)) THEN SpecDSMC(iSpec)%Init(iInit)%TVib = GETREAL('Part-Species'//TRIM(hilf2)//'-TempVib') SpecDSMC(iSpec)%Init(iInit)%TRot = GETREAL('Part-Species'//TRIM(hilf2)//'-TempRot') END IF ! read electronic temperature - IF (DSMC%ElectronicModel.GT.0) THEN + IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'EmissionDistribution')THEN + SpecDSMC(iSpec)%Init(iInit)%Telec = GETREAL('Part-Species'//TRIM(hilf2)//'-TempElec','300.0') + ELSEIF (DSMC%ElectronicModel.GT.0) THEN SpecDSMC(iSpec)%Init(iInit)%Telec = GETREAL('Part-Species'//TRIM(hilf2)//'-TempElec') END IF ! electronic model END DO !Inits diff --git a/src/timedisc/timedisc.f90 b/src/timedisc/timedisc.f90 index 799606001..ee466d2f6 100644 --- a/src/timedisc/timedisc.f90 +++ b/src/timedisc/timedisc.f90 @@ -90,7 +90,7 @@ SUBROUTINE TimeDisc() USE MOD_HDF5_Output_Particles ,ONLY: FillParticleData #endif /*PARTICLES*/ #ifdef PARTICLES -USE MOD_PICDepo ,ONLY: Deposition +!USE MOD_PICDepo ,ONLY: Deposition USE MOD_Particle_Vars ,ONLY: DoImportIMDFile #if USE_MPI USE MOD_PICDepo_Vars ,ONLY: DepositionType From 60d7501155b8cc414bb9b91cf87ab24a168f1749 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 22 Nov 2022 16:35:00 +0100 Subject: [PATCH 19/36] added removal of lines in std.out clean-up script for lines matching 'was not returned to mpool ucp_requests' (UCX warnings) --- tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py b/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py index 8a321d266..d3560e38f 100644 --- a/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py +++ b/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py @@ -114,6 +114,9 @@ def CleanSingleLines(stdfile,args): #[ Iterations: 1] #[ Norm: 0.0000000000000000] changedLines+=1 + elif line_stripped.startswith('[') and 'was not returned to mpool ucp_requests' in line and hasNumbers(line_stripped): + #[[1669126882.059241] [r34c2t5n4:1727877:0] mpool.c:54 UCX WARN object 0x1dce980 {flags:0x20040 recv length 16 host memory} was not returned to mpool ucp_requests] + changedLines+=1 else: # Write the line to the new (clean) file output_new.write(line) From 9813f90f18d79b797b40a3f9323d66b75e11042c Mon Sep 17 00:00:00 2001 From: kbpscopp Date: Tue, 22 Nov 2022 16:59:17 +0100 Subject: [PATCH 20/36] updated removal of lines in std.out clean-up script for lines matching 'was not returned to mpool ucp_requests' (UCX warnings) --- tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py b/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py index d3560e38f..459c490f0 100644 --- a/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py +++ b/tools/cleanUp_stdOut_files/cleanUp_stdOut_files.py @@ -114,7 +114,8 @@ def CleanSingleLines(stdfile,args): #[ Iterations: 1] #[ Norm: 0.0000000000000000] changedLines+=1 - elif line_stripped.startswith('[') and 'was not returned to mpool ucp_requests' in line and hasNumbers(line_stripped): + elif any(substring in line for substring in ('to mpool ucp_requests','UCX WARN','mpool.c:','ucp_requests')): + # remove UCX warnings (e.g. on hawk) #[[1669126882.059241] [r34c2t5n4:1727877:0] mpool.c:54 UCX WARN object 0x1dce980 {flags:0x20040 recv length 16 host memory} was not returned to mpool ucp_requests] changedLines+=1 else: From ee64debe54a7045a9b473ff0775abde6442b6a02 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 22 Nov 2022 17:12:21 +0100 Subject: [PATCH 21/36] abort when using BGG and UseDSMC=F --- src/particles/emission/particle_emission_init.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index eafe89106..1e8bc7dce 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -445,6 +445,8 @@ SUBROUTINE InitializeVariablesSpeciesInits() DEALLOCATE(BGGas%NumberDensity) END IF END IF ! BGGas%NumberOfSpecies.GT.0 +ELSE + IF((BGGas%NumberOfSpecies.GT.0).OR.BGGas%UseDistribution) CALL abort(__STAMP__,'BGG requires UseDSMC=T') END IF !useDSMC !-- Read Emission Distribution stuff From 64cb51652b951fdc46e89486fdcba8f86c88e04a Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 22 Nov 2022 17:36:16 +0100 Subject: [PATCH 22/36] Replaced abort() with CollectiveStop() to reduce the number of outputs when running on large core counts. --- .../emission/particle_emission_init.f90 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index 1e8bc7dce..c571c2c97 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -215,7 +215,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() BGGas%UseDistribution = GETLOGICAL('Particles-BGGas-UseDistribution') BGGas%nRegions = GETINT('Particles-BGGas-nRegions') IF(BGGas%UseDistribution.AND.(BGGas%nRegions.GT.0)) THEN - CALL abort(__STAMP__,'ERORR: Background gas can either be used with a distribution OR regions!') + CALL CollectiveStop(__STAMP__,'ERORR: Background gas can either be used with a distribution OR regions!') ELSEIF (BGGas%UseDistribution) THEN ALLOCATE(BGGas%DistributionSpeciesIndex(nSpecies)) ELSEIF (BGGas%nRegions.GT.0) THEN @@ -267,7 +267,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() Species(iSpec)%Init(iInit)%RadiusIC = GETREAL('Part-Species'//TRIM(hilf2)//'-RadiusIC') Species(iSpec)%Init(iInit)%Radius2IC = GETREAL('Part-Species'//TRIM(hilf2)//'-Radius2IC') Species(iSpec)%Init(iInit)%CylinderHeightIC = GETREAL('Part-Species'//TRIM(hilf2)//'-CylinderHeightIC') - IF(Species(iSpec)%Init(iInit)%Radius2IC.GE.Species(iSpec)%Init(iInit)%RadiusIC) CALL abort(__STAMP__,& + IF(Species(iSpec)%Init(iInit)%Radius2IC.GE.Species(iSpec)%Init(iInit)%RadiusIC) CALL CollectiveStop(__STAMP__,& 'For this emission type RadiusIC must be greater than Radius2IC!') CASE('cuboid','photon_rectangle') Species(iSpec)%Init(iInit)%CuboidHeightIC = GETREAL('Part-Species'//TRIM(hilf2)//'-CuboidHeightIC') @@ -358,13 +358,13 @@ SUBROUTINE InitializeVariablesSpeciesInits() ! Check if number density and particle number have been defined IF ((Species(iSpec)%Init(iInit)%PartDensity.GT.0.)) THEN IF (Species(iSpec)%Init(iInit)%ParticleNumber.GT.0) THEN - CALL abort(__STAMP__, 'Either ParticleNumber or PartDensity can be defined for selected parameters, not both!') + CALL CollectiveStop(__STAMP__, 'Either ParticleNumber or PartDensity can be defined for selected parameters, not both!') END IF END IF ! 2D simulation/variable time step only with cell_local and/or surface flux IF((Symmetry%Order.EQ.2).OR.VarTimeStep%UseVariableTimeStep) THEN IF (TRIM(Species(iSpec)%Init(iInit)%SpaceIC).NE.'cell_local') THEN - CALL abort(__STAMP__,'ERROR: Particle insertion/emission for 2D/axisymmetric or variable time step only possible with'//& + CALL CollectiveStop(__STAMP__,'ERROR: Particle insertion/emission for 2D/axisymmetric or variable time step only possible with'//& 'cell_local-SpaceIC and/or surface flux!') END IF END IF @@ -379,13 +379,13 @@ SUBROUTINE InitializeVariablesSpeciesInits() SWRITE(*,*) 'Part-Species[$]-Init[$]-BaseVector1IC=(/0.,1.,0/)' SWRITE(*,*) 'Part-Species[$]-Init[$]-BaseVector2IC=(/0.,0.,1/)' SWRITE(*,*) 'Part-Species[$]-Init[$]-CuboidHeightIC is the extension of the insertion region and has to be positive' - CALL abort(__STAMP__,'See above') + CALL CollectiveStop(__STAMP__,'See above') END IF END IF !--- integer check for ParticleEmissionType 2 IF((Species(iSpec)%Init(iInit)%ParticleEmissionType.EQ.2).AND. & (ABS(Species(iSpec)%Init(iInit)%ParticleNumber-INT(Species(iSpec)%Init(iInit)%ParticleNumber,8)).GT.0.0)) THEN - CALL abort(__STAMP__,' If ParticleEmissionType = 2 (parts per iteration), ParticleNumber has to be an integer number') + CALL CollectiveStop(__STAMP__,' If ParticleEmissionType = 2 (parts per iteration), ParticleNumber has to be an integer number') END IF !--- ExcludeRegions IF (Species(iSpec)%Init(iInit)%NumberOfExcludeRegions.GT.0) THEN @@ -395,7 +395,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() IF(TRIM(Species(iSpec)%Init(iInit)%SpaceIC).EQ.'background') THEN IF(BGGas%BackgroundSpecies(iSpec)) THEN ! Only regions allows multiple background inits (additionally, avoid counting the same species multiple times) - IF(.NOT.BGGas%UseRegions) CALL abort(__STAMP__, 'ERROR: Only one background definition per species is allowed!') + IF(.NOT.BGGas%UseRegions) CALL CollectiveStop(__STAMP__, 'ERROR: Only one background definition per species is allowed!') ELSE ! Count each species only once BGGas%NumberOfSpecies = BGGas%NumberOfSpecies + 1 @@ -409,7 +409,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() ELSE IF(BGGas%UseRegions) THEN Species(iSpec)%Init(iInit)%BGGRegion = GETINT('Part-Species'//TRIM(hilf2)//'-BGG-Region') IF(Species(iSpec)%Init(iInit)%BGGRegion.GT.BGGas%nRegions) THEN - CALL abort(__STAMP__, 'ERROR: Given background gas region number is greater than the defined number of regions!') + CALL CollectiveStop(__STAMP__, 'ERROR: Given background gas region number is greater than the defined number of regions!') END IF ELSE BGGas%NumberDensity(iSpec) = Species(iSpec)%Init(iInit)%PartDensity @@ -446,7 +446,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() END IF END IF ! BGGas%NumberOfSpecies.GT.0 ELSE - IF((BGGas%NumberOfSpecies.GT.0).OR.BGGas%UseDistribution) CALL abort(__STAMP__,'BGG requires UseDSMC=T') + IF((BGGas%NumberOfSpecies.GT.0).OR.BGGas%UseDistribution) CALL CollectiveStop(__STAMP__,'BGG requires UseDSMC=T') END IF !useDSMC !-- Read Emission Distribution stuff From 5598aa56147ab172198d28309276c5c1cf02a321 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 22 Nov 2022 19:55:18 +0100 Subject: [PATCH 23/36] sanity check when using different MPFs for different species. Only allow different MPFs for UseDSMC=T when also Part-vMPF=T. --- src/particles/emission/particle_emission_init.f90 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/particles/emission/particle_emission_init.f90 b/src/particles/emission/particle_emission_init.f90 index c571c2c97..c14b56135 100644 --- a/src/particles/emission/particle_emission_init.f90 +++ b/src/particles/emission/particle_emission_init.f90 @@ -200,6 +200,7 @@ SUBROUTINE InitializeVariablesSpeciesInits() ! LOCAL VARIABLES INTEGER :: iSpec, iInit CHARACTER(32) :: hilf, hilf2, DefStr +REAL :: MPFOld !=================================================================================================================================== ALLOCATE(SpecReset(1:nSpecies)) SpecReset=.FALSE. @@ -239,6 +240,11 @@ SUBROUTINE InitializeVariablesSpeciesInits() Species(iSpec)%ChargeIC = GETREAL('Part-Species'//TRIM(hilf)//'-ChargeIC') Species(iSpec)%MassIC = GETREAL('Part-Species'//TRIM(hilf)//'-MassIC') Species(iSpec)%MacroParticleFactor = GETREAL('Part-Species'//TRIM(hilf)//'-MacroParticleFactor') + IF((iSpec.GT.1).AND.UseDSMC.AND.(.NOT.UsevMPF))THEN + IF(.NOT.ALMOSTEQUALRELATIVE(Species(iSpec)%MacroParticleFactor,MPFOld,1e-5)) CALL CollectiveStop(__STAMP__,& + 'Different MPFs only allowed when using Part-vMPF=T') + END IF ! (iSpec.GT.1).AND.UseDSMC.AND.(.NOT.UsevMPF) + MPFOld = Species(iSpec)%MacroParticleFactor #if defined(IMPA) Species(iSpec)%IsImplicit = GETLOGICAL('Part-Species'//TRIM(hilf)//'-IsImplicit') #endif From 6ef3fa74e4225c3def5d76ba6054a45e6ed897a9 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 23 Nov 2022 13:43:08 +0100 Subject: [PATCH 24/36] Further reduced output to std.out during load balance --- src/analyze/analyzefield.f90 | 18 +++++------ src/equations/maxwell/equation.f90 | 31 ++++++++++--------- src/io_hdf5/hdf5_input.f90 | 11 ++++--- src/io_hdf5/hdf5_output_state.f90 | 2 +- .../pic/interpolation/init_BGField.f90 | 21 +++++++------ src/readintools/readintools.f90 | 2 +- 6 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/analyze/analyzefield.f90 b/src/analyze/analyzefield.f90 index 3e2147363..5c25010cc 100644 --- a/src/analyze/analyzefield.f90 +++ b/src/analyze/analyzefield.f90 @@ -584,6 +584,9 @@ SUBROUTINE GetPoyntingIntPlane() #if USE_MPI USE MOD_Globals #endif +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !---------------------------------------------------------------------------------------------------------------------------------- @@ -604,7 +607,7 @@ SUBROUTINE GetPoyntingIntPlane() INTEGER :: nPoyntingIntSides !< Sides for the calculation of the Poynting vector integral !=================================================================================================================================== -SWRITE(UNIT_stdOut,'(A)') ' GET PLANES TO CALCULATE POYNTING VECTOR INTEGRAL ...' +LBWRITE(UNIT_stdOut,'(A)') ' GET PLANES TO CALCULATE POYNTING VECTOR INTEGRAL ...' ! Initialize number of Poynting plane sides zero and set all sides to false nPoyntingIntSides=0 @@ -625,9 +628,7 @@ SUBROUTINE GetPoyntingIntPlane() PoyntingNormalDir1=1 PoyntingNormalDir2=2 CASE DEFAULT - CALL abort(& - __STAMP__& - ,'Poynting vector itnegral currently only in x,y,z!') + CALL CollectiveStop(__STAMP__,'Poynting vector itnegral currently only in x,y,z!') END SELECT ALLOCATE(PosPoyntingInt(nPoyntingIntPlanes)) ALLOCATE(SideIDToPoyntingSide(nSides)) @@ -697,8 +698,7 @@ SUBROUTINE GetPoyntingIntPlane() IPWRITE(UNIT_stdOut,*) " " IPWRITE(UNIT_stdOut,*) "Found illegal Poyting plane side. SideID= ",SideID,& " z-coordinate= ",PosPoyntingInt(iPlane) - CALL abort(& - __STAMP__& + CALL abort(__STAMP__& ,'GetPoyntingIntPlane: Found SideID for Poynting vector integral which is attached to an element'//& ' within which the dielectric permittivity mu_r is not euqal to 1.0 everywhere. The value could be'//& ' unequal to 1.0 on the interface and this is not implemented. TODO: determine mu_r on interface,'//& @@ -753,15 +753,15 @@ SUBROUTINE GetPoyntingIntPlane() #endif /*USE_MPI*/ DO iPlane= 1, nPoyntingIntPlanes - SWRITE(UNIT_stdOut,'(A,I2,A,I10,A)') 'Processed plane no.: ',iPlane,'. Found ',sumFaces(iPlane),' surfaces.' + LBWRITE(UNIT_stdOut,'(A,I2,A,I10,A)') 'Processed plane no.: ',iPlane,'. Found ',sumFaces(iPlane),' surfaces.' END DO -SWRITE(UNIT_stdOut,'(A,I10,A)') 'A total of',sumAllFaces, & +LBWRITE(UNIT_stdOut,'(A,I10,A)') 'A total of',sumAllFaces, & ' surfaces for the poynting vector integral calculation are found.' ALLOCATE(S (1:3,0:PP_N,0:PP_N,1:nPoyntingIntSides) , & STEM (0:PP_N,0:PP_N,1:nPoyntingIntSides) ) -SWRITE(UNIT_stdOut,'(A)') ' ... POYNTING VECTOR INTEGRAL INITIALIZATION DONE.' +LBWRITE(UNIT_stdOut,'(A)') ' ... POYNTING VECTOR INTEGRAL INITIALIZATION DONE.' END SUBROUTINE GetPoyntingIntPlane diff --git a/src/equations/maxwell/equation.f90 b/src/equations/maxwell/equation.f90 index 88729d5c6..5d6f1b846 100644 --- a/src/equations/maxwell/equation.f90 +++ b/src/equations/maxwell/equation.f90 @@ -1278,6 +1278,9 @@ SUBROUTINE GetWaveGuideRadius(DoSide) USE MOD_Basis, ONLY:BarycentricWeights,InitializeVandermonde USE MOD_Interpolation_Vars, ONLY:xGP,wBary #endif +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ !----------------------------------------------------------------------------------------------------------------------------------! ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE @@ -1326,7 +1329,7 @@ SUBROUTINE GetWaveGuideRadius(DoSide) CALL MPI_ALLREDUCE(MPI_IN_PLACE,TERadius,1,MPI_DOUBLE_PRECISION,MPI_MAX,MPI_COMM_WORLD,iError) #endif /*USE_MPI*/ -SWRITE(UNIT_StdOut,*) ' Found waveguide radius of ', TERadius +LBWRITE(UNIT_StdOut,*) ' Found waveguide radius of ', TERadius END SUBROUTINE GetWaveGuideRadius @@ -1337,14 +1340,17 @@ SUBROUTINE InitExactFlux() !=================================================================================================================================== ! MODULES USE MOD_PreProc -USE MOD_Globals, ONLY:abort,UNIT_stdOut,mpiroot +USE MOD_Globals ,ONLY: abort,UNIT_stdOut,mpiroot,CollectiveStop #if USE_MPI -USE MOD_Globals, ONLY:MPI_COMM_WORLD,MPI_SUM,MPI_INTEGER,IERROR +USE MOD_Globals ,ONLY: MPI_COMM_WORLD,MPI_SUM,MPI_INTEGER,IERROR #endif -USE MOD_Mesh_Vars, ONLY:nElems,ElemToSide,SideToElem,lastMPISide_MINE -USE MOD_Interfaces, ONLY:FindElementInRegion,FindInterfacesInRegion,CountAndCreateMappings -USE MOD_Equation_Vars, ONLY:ExactFluxDir,ExactFluxPosition,isExactFluxInterFace -USE MOD_ReadInTools, ONLY:GETREAL,GETINT +USE MOD_Mesh_Vars ,ONLY: nElems,ElemToSide,SideToElem,lastMPISide_MINE +USE MOD_Interfaces ,ONLY: FindElementInRegion,FindInterfacesInRegion,CountAndCreateMappings +USE MOD_Equation_Vars ,ONLY: ExactFluxDir,ExactFluxPosition,isExactFluxInterFace +USE MOD_ReadInTools ,ONLY: GETREAL,GETINT +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- @@ -1377,9 +1383,7 @@ SUBROUTINE InitExactFlux() CASE(3) ! z InterFaceRegion(1:6)=(/-HUGE(1.),HUGE(1.),-HUGE(1.),HUGE(1.),-HUGE(1.),ExactFluxPosition/) CASE DEFAULT - CALL abort(& - __STAMP__& - ,' Unknown exact flux direction: ExactFluxDir=',ExactFluxDir) + CALL CollectiveStop(__STAMP__,' Unknown exact flux direction: ExactFluxDir=',ExactFluxDir) END SELECT ! set all elements lower/higher than the ExactFluxPosition to True/False for interface determination @@ -1406,12 +1410,11 @@ SUBROUTINE InitExactFlux() #else sumExactFluxMasterInterFaces=nExactFluxMasterInterFaces #endif /*USE_MPI*/ -SWRITE(UNIT_StdOut,'(A8,I10,A)') ' Found ',sumExactFluxMasterInterFaces,' interfaces for ExactFlux.' +LBWRITE(UNIT_StdOut,'(A8,I10,A)') ' Found ',sumExactFluxMasterInterFaces,' interfaces for ExactFlux.' IF(mpiroot)THEN IF(sumExactFluxMasterInterFaces.LE.0)THEN - CALL abort(& - __STAMP__& + CALL abort(__STAMP__& ,' [sumExactFluxMasterInterFaces.LE.0]: using ExactFlux but no interfaces found: sumExactFlux=',sumExactFluxMasterInterFaces) END IF END IF @@ -1431,7 +1434,7 @@ SUBROUTINE InitExactFlux() #else sumExactFluxMasterInterFaces=nExactFluxMasterInterFaces #endif /*USE_MPI*/ -SWRITE(UNIT_StdOut,'(A8,I10,A)') ' Found ',sumExactFluxMasterInterFaces,' interfaces for ExactFlux. <<<<<< DEBUG this' +LBWRITE(UNIT_StdOut,'(A8,I10,A)') ' Found ',sumExactFluxMasterInterFaces,' interfaces for ExactFlux. <<<<<< DEBUG this' diff --git a/src/io_hdf5/hdf5_input.f90 b/src/io_hdf5/hdf5_input.f90 index 063bf8351..60b207006 100644 --- a/src/io_hdf5/hdf5_input.f90 +++ b/src/io_hdf5/hdf5_input.f90 @@ -339,6 +339,9 @@ SUBROUTINE GetDataProps(DatasetName,nVar_HDF5,N_HDF5,nElems_HDF5,NodeType_HDF5,n ! MODULES USE MOD_Globals USE MOD_ReadInTools ,ONLY: PrintOption +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ IMPLICIT NONE !---------------------------------------------------------------------------------------------------------------------------------- ! INPUT/OUTPUT VARIABLES @@ -354,8 +357,8 @@ SUBROUTINE GetDataProps(DatasetName,nVar_HDF5,N_HDF5,nElems_HDF5,NodeType_HDF5,n INTEGER(HID_T) :: Dset_ID,FileSpace INTEGER(HSIZE_T), DIMENSION(7) :: Dims,DimsMax !================================================================================================================================== -SWRITE(UNIT_stdOut,'(132("-"))') -SWRITE(UNIT_stdOut,'(A,A)')' GET SIZE OF DATA IN HDF5 FILE... ' +LBWRITE(UNIT_stdOut,'(132("-"))') +LBWRITE(UNIT_stdOut,'(A,A)')' GET SIZE OF DATA IN HDF5 FILE... ' ! Dimensional shift (optional) if arrays with rank > 5 are processed (e.g. DG_Solution from state files with an additional ! dimension that corresponds to time) @@ -401,8 +404,8 @@ SUBROUTINE GetDataProps(DatasetName,nVar_HDF5,N_HDF5,nElems_HDF5,NodeType_HDF5,n nElems_HDF5 = INT(Dims(Rank-nDimsOffset_loc),4) CALL PrintOption('Number of Elements','HDF5',IntOpt=nElems_HDF5) ! 'HDF5.' -SWRITE(UNIT_stdOut,'(A)')' DONE!' -SWRITE(UNIT_stdOut,'(132("-"))') +LBWRITE(UNIT_stdOut,'(A)')' DONE!' +LBWRITE(UNIT_stdOut,'(132("-"))') END SUBROUTINE GetDataProps diff --git a/src/io_hdf5/hdf5_output_state.f90 b/src/io_hdf5/hdf5_output_state.f90 index 754c80468..9106fecee 100644 --- a/src/io_hdf5/hdf5_output_state.f90 +++ b/src/io_hdf5/hdf5_output_state.f90 @@ -480,7 +480,7 @@ SUBROUTINE WriteStateToHDF5(MeshFileName,OutputTime,PreviousTime) #if USE_MPI CALL MPI_BARRIER(MPI_COMM_WORLD,iError) #endif /*USE_MPI*/ - IF(OutPutSource) THEN + IF(OutputSource) THEN #if USE_HDG ! Add BR electron fluid density to PartSource for output to state.h5 IF(UseBRElectronFluid) CALL AddBRElectronFluidToPartSource() diff --git a/src/particles/pic/interpolation/init_BGField.f90 b/src/particles/pic/interpolation/init_BGField.f90 index 8d2b5120c..c4cbc6338 100644 --- a/src/particles/pic/interpolation/init_BGField.f90 +++ b/src/particles/pic/interpolation/init_BGField.f90 @@ -78,6 +78,9 @@ SUBROUTINE InitializeBackgroundField USE MOD_ReadInTools ,ONLY: PrintOption USE MOD_SuperB ,ONLY: SuperB USE MOD_SuperB_Vars ,ONLY: BGFieldFrequency,UseTimeDepCoil,nTimePoints,BGFieldTDep +#if USE_LOADBALANCE +USE MOD_LoadBalance_Vars ,ONLY: PerformLoadBalance +#endif /*USE_LOADBALANCE*/ ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !---------------------------------------------------------------------------------------------------------------------------------- @@ -97,8 +100,8 @@ SUBROUTINE InitializeBackgroundField LOGICAL :: BGFieldExists,DG_SolutionExists !=================================================================================================================================== -SWRITE(UNIT_stdOut,'(132("-"))') -SWRITE(UNIT_stdOut,'(A)')' INIT BACKGROUND FIELD...' +LBWRITE(UNIT_stdOut,'(132("-"))') +LBWRITE(UNIT_stdOut,'(A)')' INIT BACKGROUND FIELD...' ! 1) Determine whether a field will be read-in or calculated UseTimeDepCoil=.FALSE.! Initialize @@ -111,8 +114,8 @@ SUBROUTINE InitializeBackgroundField IF(FILEEXISTS(TRIM(BGFileName))) THEN ! 1b) If a filename not given, check if the BGField for the current case exists, if it does -> read-in of the available field CalcBField = .FALSE. - SWRITE(UNIT_stdOut,'(A)')' No file name for the background field was given, but an existing file was found!' - SWRITE(UNIT_stdOut,*) 'File name: ', TRIM(BGFileName) + LBWRITE(UNIT_stdOut,'(A)')' No file name for the background field was given, but an existing file was found!' + LBWRITE(UNIT_stdOut,*) 'File name: ', TRIM(BGFileName) ELSE ! 1c) If no filename was given and no current BGField for this case exists, check if permanent magnets/coils were given -> superB CalcBField = .TRUE. @@ -171,7 +174,7 @@ SUBROUTINE InitializeBackgroundField ! Calculate the background B-field via SuperB CALL SuperB() ELSE - SWRITE(UNIT_stdOut,'(A)')' Reading background field from file ['//TRIM(BGFileName)//']... ' + LBWRITE(UNIT_stdOut,'(A)')' Reading background field from file ['//TRIM(BGFileName)//']... ' ALLOCATE(VarNames(nVar_BField)) CALL ReadAttribute(File_ID,'VarNames',nVar_BField,StrArray=VarNames) @@ -241,9 +244,9 @@ SUBROUTINE InitializeBackgroundField ! END IF IF(NBG.NE.N_In)THEN - SWRITE(UNIT_stdOut,'(A)')' Changing polynomial degree of BG-Field.' + LBWRITE(UNIT_stdOut,'(A)')' Changing polynomial degree of BG-Field.' IF(NBG.GT.N_IN) THEN - SWRITE(UNIT_stdOut,'(A)')' WARNING: BG-Field is used with higher polynomial degree than given!' + LBWRITE(UNIT_stdOut,'(A)')' WARNING: BG-Field is used with higher polynomial degree than given!' END IF ALLOCATE( Vdm_BGFieldIn_BGField(0:NBG,0:N_IN) & , wGP_tmp(0:N_in) & @@ -293,8 +296,8 @@ SUBROUTINE InitializeBackgroundField SDEALLOCATE(xGP_tmp) END IF ! CalcBField -SWRITE(UNIT_stdOut,'(A)')' INIT BACKGROUND FIELD DONE!' -SWRITE(UNIT_StdOut,'(132("-"))') +LBWRITE(UNIT_stdOut,'(A)')' INIT BACKGROUND FIELD DONE!' +LBWRITE(UNIT_StdOut,'(132("-"))') END SUBROUTINE InitializeBackgroundField diff --git a/src/readintools/readintools.f90 b/src/readintools/readintools.f90 index 7f16b8f45..500e204c5 100644 --- a/src/readintools/readintools.f90 +++ b/src/readintools/readintools.f90 @@ -2204,7 +2204,7 @@ SUBROUTINE PrintOption(NameOpt,InfoOpt,IntOpt,IntArrayOpt,RealOpt,LogOpt,LogArra #if USE_LOADBALANCE IF (PerformLoadBalance) THEN SELECT CASE(TRIM(InfoOpt)) - CASE("INFO","PARAM","CALCUL.","OUTPUT") + CASE("INFO","PARAM","CALCUL.","OUTPUT","HDF5") RETURN END SELECT END IF From 71954122343c7587e55e1a11fa0627a1ff0fc90d Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Wed, 23 Nov 2022 18:49:01 +0100 Subject: [PATCH 25/36] fixed particle delay time in combination with LB restarts --- src/particles/restart/particle_readin.f90 | 39 +++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/particles/restart/particle_readin.f90 b/src/particles/restart/particle_readin.f90 index dd64c3dff..751d54462 100644 --- a/src/particles/restart/particle_readin.f90 +++ b/src/particles/restart/particle_readin.f90 @@ -72,6 +72,9 @@ SUBROUTINE ParticleReadin() USE MOD_Particle_Mesh_Vars ,ONLY: ElemNodeID_Shared,NodeInfo_Shared,nUniqueGlobalNodes USE MOD_Mesh_Tools ,ONLY: GetCNElemID USE MOD_Mesh_Vars ,ONLY: offsetElem +USE MOD_Particle_Vars ,ONLY: DelayTime +USE MOD_PICDepo_Vars ,ONLY: PartSource +USE MOD_TimeDisc_Vars ,ONLY: time #endif /*USE_LOADBALANCE*/ USE MOD_Particle_Vars ,ONLY: VibQuantData,ElecDistriData,AD_Data USE MOD_Particle_Vars ,ONLY: PartDataSize,PartIntSize @@ -135,7 +138,9 @@ SUBROUTINE ParticleReadin() ! ------------------------------------------------ ! PartSource ! ------------------------------------------------ - IF (DoDeposition .AND. RelaxDeposition) THEN + ! 1.) relax deposition + ! 2.) particle delay time active + IF (DoDeposition .AND. (RelaxDeposition.OR.(time.LT.DelayTime))) THEN ALLOCATE(PartSource_HDF5(1:4,0:PP_N,0:PP_N,0:PP_N,nElems)) ASSOCIATE (& counts_send => INT(MPInElemSend ) ,& @@ -153,17 +158,33 @@ SUBROUTINE ParticleReadin() END ASSOCIATE DEALLOCATE(PartSourceLB) - DO iElem =1,PP_nElems - DO k=0, PP_N; DO j=0, PP_N; DO i=0, PP_N + ! 1.) relax deposition + IF(RelaxDeposition)THEN + DO iElem =1,PP_nElems + DO k=0, PP_N; DO j=0, PP_N; DO i=0, PP_N #if ((USE_HDG) && (PP_nVar==1)) - PartSourceOld(1,1,i,j,k,iElem) = PartSource_HDF5(4,i,j,k,iElem) - PartSourceOld(1,2,i,j,k,iElem) = PartSource_HDF5(4,i,j,k,iElem) + PartSourceOld(1,1,i,j,k,iElem) = PartSource_HDF5(4,i,j,k,iElem) + PartSourceOld(1,2,i,j,k,iElem) = PartSource_HDF5(4,i,j,k,iElem) #else - PartSourceOld(1:4,1,i,j,k,iElem) = PartSource_HDF5(1:4,i,j,k,iElem) - PartSourceOld(1:4,2,i,j,k,iElem) = PartSource_HDF5(1:4,i,j,k,iElem) + PartSourceOld(1:4,1,i,j,k,iElem) = PartSource_HDF5(1:4,i,j,k,iElem) + PartSourceOld(1:4,2,i,j,k,iElem) = PartSource_HDF5(1:4,i,j,k,iElem) #endif - END DO; END DO; END DO - END DO + END DO; END DO; END DO + END DO + END IF ! RelaxDeposition + + ! 2.) particle delay time active + IF(time.LT.DelayTime)THEN + DO iElem =1,PP_nElems + DO k=0, PP_N; DO j=0, PP_N; DO i=0, PP_N +#if ((USE_HDG) && (PP_nVar==1)) + PartSource(1,i,j,k,iElem) = PartSource_HDF5(4,i,j,k,iElem) +#else + PartSource(1:4,i,j,k,iElem) = PartSource_HDF5(1:4,i,j,k,iElem) +#endif + END DO; END DO; END DO + END DO + END IF ! time.LE.DelayTime END IF ! (DoDeposition .AND. RelaxDeposition) ! ------------------------------------------------ From ea2b1b9f9b924e036796ac216ee6c914eb7bc47b Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Thu, 24 Nov 2022 15:57:37 +0100 Subject: [PATCH 26/36] Fixed memory leaks in combination with Part-DelayTime>0 --- src/mesh/mesh_readin.f90 | 3 +-- src/timedisc/timedisc_TimeStepByLSERK.f90 | 11 ++++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/mesh/mesh_readin.f90 b/src/mesh/mesh_readin.f90 index 460258b6a..93f50ea9b 100644 --- a/src/mesh/mesh_readin.f90 +++ b/src/mesh/mesh_readin.f90 @@ -603,8 +603,7 @@ SUBROUTINE ReadMesh(FileString) aSide%connection%Elem=>GETNEWELEM() aSide%NbProc = ELEMIPROC(elemID) #else - CALL abort(__STAMP__, & - ' ElemID of neighbor not in global Elem list ') + CALL abort(__STAMP__, ' ElemID of neighbor not in global Elem list ') #endif END IF END IF diff --git a/src/timedisc/timedisc_TimeStepByLSERK.f90 b/src/timedisc/timedisc_TimeStepByLSERK.f90 index 019ccdeb1..0d54f8b7d 100644 --- a/src/timedisc/timedisc_TimeStepByLSERK.f90 +++ b/src/timedisc/timedisc_TimeStepByLSERK.f90 @@ -114,7 +114,7 @@ SUBROUTINE TimeStepByLSERK() CALL LBStartTime(tLBStart) #endif /*USE_LOADBALANCE*/ #if USE_MPI - CALL IRecvNbofParticles() + IF(time.GE.DelayTime) CALL IRecvNbofParticles() #endif /*USE_MPI*/ #if USE_LOADBALANCE @@ -130,12 +130,9 @@ SUBROUTINE TimeStepByLSERK() CALL CountPartsPerElem(ResetNumberOfParticles=.TRUE.) !for scaling of tParts of LB. Also done for state output of PartsPerElem - IF ((time.GE.DelayTime).OR.(iter.EQ.0)) THEN - ! Forces on particle - IF (time.GE.DelayTime) CALL InterpolateFieldToParticle() - END IF - + ! Forces on particle IF (time.GE.DelayTime) THEN + CALL InterpolateFieldToParticle() IF(DoFieldIonization) CALL FieldIonization() IF(DoInterpolation) CALL CalcPartRHS() END IF @@ -191,7 +188,7 @@ SUBROUTINE TimeStepByLSERK() CALL extrae_eventandcounters(int(9000001), int8(0)) #endif /*EXTRAE*/ - IF ((time.GE.DelayTime).OR.(iter.EQ.0)) THEN + IF (time.GE.DelayTime) THEN IF(MeasureTrackTime) CALL CPU_TIME(TimeStart) CALL PerformTracking() #ifdef EXTRAE From 631254899bbfc5b8549b87727469be9c1f123eb6 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Sun, 27 Nov 2022 23:12:49 +0100 Subject: [PATCH 27/36] Added RAM monitoring that outputs a warning when 95% of the maximum available RAM is reached. Currently, RAM usage is measured in each time step. --- src/analyze/analyze.f90 | 3 +- src/globals/globals_init.f90 | 5 +- src/globals/globals_vars.f90 | 4 +- src/init/define_parameters_init.f90 | 6 +- src/loadbalance/loaddistribution.f90 | 136 ++++++++++++++++----------- src/mpi/mpi_shared.f90 | 15 ++- src/mpi/mpi_shared_vars.f90 | 5 + 7 files changed, 112 insertions(+), 62 deletions(-) diff --git a/src/analyze/analyze.f90 b/src/analyze/analyze.f90 index 70bf87b72..5dce008ab 100644 --- a/src/analyze/analyze.f90 +++ b/src/analyze/analyze.f90 @@ -911,6 +911,7 @@ SUBROUTINE PerformAnalyze(OutputTime,FirstOrLastIter,OutPutHDF5) #ifdef PARTICLES USE MOD_PICDepo_Vars ,ONLY: DoDeposition, RelaxDeposition #endif /*PARTICLES*/ +USE MOD_TimeDisc_Vars ,ONLY: time ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !---------------------------------------------------------------------------------------------------------------------------------- @@ -967,7 +968,7 @@ SUBROUTINE PerformAnalyze(OutputTime,FirstOrLastIter,OutPutHDF5) #endif /*EXTRAE*/ ! Create .csv file for performance analysis and load balance: write header line -CALL WriteElemTimeStatistics(WriteHeader=.TRUE.,iter_opt=iter) +CALL WriteElemTimeStatistics(WriteHeader=.TRUE.,iter_opt=iter,time_opt=time) ! check if final/last iteration iteration LastIter=.FALSE. diff --git a/src/globals/globals_init.f90 b/src/globals/globals_init.f90 index 37b34278c..19ddd0aee 100644 --- a/src/globals/globals_init.f90 +++ b/src/globals/globals_init.f90 @@ -66,7 +66,7 @@ SUBROUTINE InitGlobals() ! MODULES USE MOD_PreProc USE MOD_Globals ,ONLY: LogFile,UNIT_StdOut,UNIT_logOut,Logging,myRank,abort -USE MOD_Globals_Vars ,ONLY: c,eps0,mu0,ProjectName +USE MOD_Globals_Vars ,ONLY: c,eps0,mu0,ProjectName,memory #if USE_READIN_CONSTANTS USE MOD_Globals_Vars ,ONLY: c_inv,c2,c2_inv,smu0,RelativisticLimit USE MOD_ReadInTools ,ONLY: GETREAL @@ -96,6 +96,9 @@ SUBROUTINE InitGlobals() SWRITE(UNIT_StdOut,'(132("-"))') SWRITE(UNIT_stdOut,'(A)')' INIT GLOBALS ...' +! RAM monitor +memory = 0. + #if USE_READIN_CONSTANTS ! Natural constants c = GETREAL('c0') diff --git a/src/globals/globals_vars.f90 b/src/globals/globals_vars.f90 index 982927ef6..b2600d99d 100644 --- a/src/globals/globals_vars.f90 +++ b/src/globals/globals_vars.f90 @@ -40,8 +40,8 @@ MODULE MOD_Globals_Vars REAL :: SimulationEfficiency !> relates the simulated time to the used CPUh (SIMULATION TIME PER !> CALCULATION in [s]/[CPUh]) REAL :: StartT !> Timer start -REAL :: PID !> Performance index: (CalcTimeEnd-CalcTimeStart)*nProcessors/ - !> (nGlobalElems*(PP_N+1)**3*iter_loc) +REAL :: PID !> Performance index: (CalcTimeEnd-CalcTimeStart)*nProcessors/(nGlobalElems*(PP_N+1)**3*iter_loc) +REAL :: memory(1:4) !> RAM: used, available, total and initial (total at the beginning of the simulation) REAL,PARAMETER :: PI=ACOS(-1.0) !> the number pi ~= 3.14 REAL,PARAMETER :: sPI=1.0/PI !> inverse of pi REAL,PARAMETER :: epsMach=EPSILON(0.0) !> Machine accuracy diff --git a/src/init/define_parameters_init.f90 b/src/init/define_parameters_init.f90 index 5b0b51267..09eb18a6c 100644 --- a/src/init/define_parameters_init.f90 +++ b/src/init/define_parameters_init.f90 @@ -30,6 +30,7 @@ SUBROUTINE InitDefineParameters() USE MOD_Globals ,ONLY: UNIT_stdOut #if USE_MPI USE MOD_Globals ,ONLY: MPIRoot +USE MOD_MPI_Shared ,ONLY: DefineParametersMPIShared #endif /*USE_MPI*/ USE MOD_Globals_Init ,ONLY: DefineParametersGlobals USE MOD_ReadInTools ,ONLY: prms @@ -81,7 +82,7 @@ SUBROUTINE InitDefineParameters() USE MOD_SuperB_Init ,ONLY: DefineParametersSuperB #if USE_MPI USE mod_readIMD ,ONLY: DefineParametersReadIMDdata -#endif /* USE_MPI */ +#endif #endif !----------------------------------------------------------------------------------------------------------------------------------! ! Insert modules here @@ -97,6 +98,9 @@ SUBROUTINE InitDefineParameters() SWRITE(UNIT_stdOut,'(132("="))') CALL DefineParametersMPI() +#if USE_MPI +CALL DefineParametersMPIShared() +#endif /*USE_MPI*/ CALL DefineParametersIO() CALL DefineParametersGlobals() CALL DefineParametersLoadBalance() diff --git a/src/loadbalance/loaddistribution.f90 b/src/loadbalance/loaddistribution.f90 index c391f034a..24c1f98c5 100644 --- a/src/loadbalance/loaddistribution.f90 +++ b/src/loadbalance/loaddistribution.f90 @@ -1227,7 +1227,7 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) ! MODULES USE MOD_LoadBalance_Vars ,ONLY: TargetWeight,nLoadBalanceSteps,CurrentImbalance,MinWeight,MaxWeight,WeightSum USE MOD_Globals ,ONLY: MPIRoot,FILEEXISTS,unit_stdout,abort,nProcessors,ProcessMemUsage,nProcessors -USE MOD_Globals_Vars ,ONLY: SimulationEfficiency,PID,WallTime,InitializationWallTime,ReadMeshWallTime +USE MOD_Globals_Vars ,ONLY: SimulationEfficiency,PID,WallTime,InitializationWallTime,ReadMeshWallTime,memory USE MOD_Globals_Vars ,ONLY: DomainDecompositionWallTime,CommMeshReadinWallTime USE MOD_Restart_Vars ,ONLY: DoRestart #ifdef PARTICLES @@ -1238,8 +1238,12 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) #if USE_MPI USE MOD_MPI_Shared_Vars ,ONLY: myComputeNodeRank,myLeaderGroupRank USE MOD_Globals -USE MOD_MPI_Shared_Vars ,ONLY: MPI_COMM_LEADERS_SHARED,MPI_COMM_SHARED +USE MOD_MPI_Shared_Vars ,ONLY: MPI_COMM_LEADERS_SHARED,MPI_COMM_SHARED,MemoryMonitor +#if ! (CORE_SPLIT==0) +USE MOD_MPI_Shared_Vars ,ONLY: NbrOfPhysicalNodes,nLeaderGroupProcs +#endif /*! (CORE_SPLIT==0)*/ #endif /*USE_MPI*/ +USE MOD_StringTools ,ONLY: set_formatting,clear_formatting ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------! @@ -1289,11 +1293,11 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) CHARACTER(LEN=255) :: tmpStr(nOutputVar) ! needed because PerformAnalyze is called multiple times at the beginning CHARACTER(LEN=1000) :: tmpStr2 CHARACTER(LEN=1),PARAMETER :: delimiter="," -REAL :: memory(1:3) ! used, available and total #if USE_MPI REAL :: ProcMemoryUsed ! Used memory on a single proc REAL :: NodeMemoryUsed ! Sum of used memory across one compute node #endif /*USE_MPI*/ +REAL :: MemUsagePercent !=================================================================================================================================== ! Get process memory info @@ -1314,9 +1318,9 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) ! collect data from node roots on first root node IF (myComputeNodeRank.EQ.0) THEN ! only leaders IF (myLeaderGroupRank.EQ.0) THEN ! first node leader MUST be MPIRoot - CALL MPI_REDUCE(MPI_IN_PLACE , memory , 3 , MPI_DOUBLE_PRECISION , MPI_SUM , 0 , MPI_COMM_LEADERS_SHARED , IERROR) + CALL MPI_REDUCE(MPI_IN_PLACE , memory(1:3) , 3 , MPI_DOUBLE_PRECISION , MPI_SUM , 0 , MPI_COMM_LEADERS_SHARED , IERROR) ELSE - CALL MPI_REDUCE(memory , 0 , 3 , MPI_DOUBLE_PRECISION , MPI_SUM , 0 , MPI_COMM_LEADERS_SHARED , IERROR) + CALL MPI_REDUCE(memory(1:3) , 0 , 3 , MPI_DOUBLE_PRECISION , MPI_SUM , 0 , MPI_COMM_LEADERS_SHARED , IERROR) END IF ! myLeaderGroupRank.EQ.0 END IF ! myComputeNodeRank.EQ.0 END IF ! nProcessors.EQ.1 @@ -1328,13 +1332,33 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) IF(.NOT.MPIRoot)RETURN ! Convert kB to GB -memory=memory/1048576. +memory(1:3)=memory(1:3)/1048576. #if ! (CORE_SPLIT==0) - ! When core-level splitting is used, it is not clear how many cores are on the same physical compute node. - ! Therefore, the values are set to -1. +! When core-level splitting is used, it is not clear how many cores are on the same physical compute node. +! Therefore, the values are set to -1. +IF(NbrOfPhysicalNodes.GT.0)THEN + memory(2:3) = memory(2:3) * REAL(NbrOfPhysicalNodes) / REAL(nLeaderGroupProcs) +ELSE memory(2:3) = -1. +END IF ! NbrOfPhysicalNodes.GT.0 #endif /*! (CORE_SPLIT==0)*/ +! Check for memory leaks +IF(MemoryMonitor)THEN + IF(memory(4).LE.0.)THEN + memory(4) = memory(1) ! Store total initially used memory + ELSE + ! Check if more memory is used than at the beginning AND 95% of the total memory available is reached + MemUsagePercent = (memory(1)/memory(3))*100.0 + !MemUsagePercent = 99.32 + IF((memory(1).GT.memory(4)).AND.(MemUsagePercent.GT.95.0))THEN + CALL set_formatting("red") + SWRITE(UNIT_stdOut,'(A,F5.2,A)') ' WARNING: Memory reaching maximum, RAM is at ',MemUsagePercent,'%' + CALL clear_formatting() + END IF + END IF ! WriteHeader +END IF ! MemoryMonitor + ! Either create new file or add info to existing file !> create new file IF(WriteHeader)THEN @@ -1368,59 +1392,59 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the temporary string CLOSE(ioUnit) -ELSE ! - IF(PRESENT(time_opt))THEN - time_loc = time_opt - ELSE - time_loc = -1. - END IF +END IF + +IF(PRESENT(time_opt))THEN + time_loc = time_opt +ELSE + time_loc = -1. +END IF #ifdef PARTICLES - ! Calculate elem time proportions for field and particle routines - SumElemTime=ElemTimeField+ElemTimePart - IF(SumElemTime.LE.0.)THEN - ElemTimeFieldPercent = 0. - ElemTimePartPercent = 0. - ELSE - ElemTimeFieldPercent = 100. * ElemTimeField / SumElemTime - ElemTimePartPercent = 100. * ElemTimePart / SumElemTime - END IF ! ElemTimeField+ElemTimePart.LE.0. +! Calculate elem time proportions for field and particle routines +SumElemTime=ElemTimeField+ElemTimePart +IF(SumElemTime.LE.0.)THEN + ElemTimeFieldPercent = 0. + ElemTimePartPercent = 0. +ELSE + ElemTimeFieldPercent = 100. * ElemTimeField / SumElemTime + ElemTimePartPercent = 100. * ElemTimePart / SumElemTime +END IF ! ElemTimeField+ElemTimePart.LE.0. #endif /*PARTICLES*/ - IF (FILEEXISTS(outfile)) THEN - OPEN(NEWUNIT=ioUnit,FILE=TRIM(outfile),POSITION="APPEND",STATUS="OLD") - WRITE(formatStr,'(A2,I2,A14,A1)')'(',nOutputVar,CSVFORMAT,')' - WRITE(tmpStr2,formatStr)& - " ",time_loc ,& - delimiter,REAL(nProcessors) ,& - delimiter,MinWeight ,& - delimiter,MaxWeight ,& - delimiter,CurrentImbalance ,& - delimiter,TargetWeight ,& - delimiter,REAL(nLoadBalanceSteps) ,& - delimiter,WeightSum ,& - delimiter,SimulationEfficiency ,& - delimiter,PID ,& - delimiter,WallTime ,& - delimiter,DomainDecompositionWallTime,& - delimiter,CommMeshReadinWallTime ,& - delimiter,ReadMeshWallTime ,& - delimiter,InitializationWallTime ,& - delimiter,memory(1) ,& - delimiter,memory(2) ,& - delimiter,memory(3) & +IF (FILEEXISTS(outfile)) THEN + OPEN(NEWUNIT=ioUnit,FILE=TRIM(outfile),POSITION="APPEND",STATUS="OLD") + WRITE(formatStr,'(A2,I2,A14,A1)')'(',nOutputVar,CSVFORMAT,')' + WRITE(tmpStr2,formatStr)& + " ",time_loc ,& + delimiter,REAL(nProcessors) ,& + delimiter,MinWeight ,& + delimiter,MaxWeight ,& + delimiter,CurrentImbalance ,& + delimiter,TargetWeight ,& + delimiter,REAL(nLoadBalanceSteps) ,& + delimiter,WeightSum ,& + delimiter,SimulationEfficiency ,& + delimiter,PID ,& + delimiter,WallTime ,& + delimiter,DomainDecompositionWallTime,& + delimiter,CommMeshReadinWallTime ,& + delimiter,ReadMeshWallTime ,& + delimiter,InitializationWallTime ,& + delimiter,memory(1) ,& + delimiter,memory(2) ,& + delimiter,memory(3) & #ifdef PARTICLES - ,delimiter,REAL(nGlobalNbrOfParticles(3)),& - delimiter,ElemTimeField ,& - delimiter,ElemTimePart ,& - delimiter,ElemTimeFieldPercent ,& - delimiter,ElemTimePartPercent + ,delimiter,REAL(nGlobalNbrOfParticles(3)),& + delimiter,ElemTimeField ,& + delimiter,ElemTimePart ,& + delimiter,ElemTimeFieldPercent ,& + delimiter,ElemTimePartPercent #endif /*PARTICLES*/ - ; ! this is required for terminating the "&" when particles=off - WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the data line - CLOSE(ioUnit) - ELSE - WRITE(UNIT_stdOut,'(A)')TRIM(outfile)//" does not exist. Cannot write load balance info!" - END IF + ; ! this is required for terminating the "&" when particles=off + WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the data line + CLOSE(ioUnit) +ELSE + WRITE(UNIT_stdOut,'(A)')TRIM(outfile)//" does not exist. Cannot write load balance info!" END IF END SUBROUTINE WriteElemTimeStatistics diff --git a/src/mpi/mpi_shared.f90 b/src/mpi/mpi_shared.f90 index 1aa49da03..c4689464c 100644 --- a/src/mpi/mpi_shared.f90 +++ b/src/mpi/mpi_shared.f90 @@ -99,7 +99,10 @@ SUBROUTINE DefineParametersMPIShared() !---------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES !================================================================================================================================== -CALL prms%SetSection ("MPI Shared") +CALL prms%SetSection( 'MPI Shared') +#if ! (CORE_SPLIT==0) +CALL prms%CreateIntOption('NbrOfPhysicalNodes' , 'Number of physical nodes (as opposed to virtual nodes). Required for RAM monitoring when using more than one virtual compute node per physical node.', '-1') +#endif /*! (CORE_SPLIT==0)*/ END SUBROUTINE DefineParametersMPIShared @@ -112,6 +115,9 @@ SUBROUTINE InitMPIShared() USE MOD_Globals USE MOD_MPI_Vars USE MOD_MPI_Shared_Vars +#if ! (CORE_SPLIT==0) +USE MOD_Readintools ,ONLY: GETINT +#endif /*! (CORE_SPLIT==0)*/ ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !---------------------------------------------------------------------------------------------------------------------------------- @@ -126,6 +132,13 @@ SUBROUTINE InitMPIShared() ! Save the global number of procs nProcessors_Global = nProcessors +MemoryMonitor = .TRUE. +#if ! (CORE_SPLIT==0) +! When core-level splitting is used, it is not clear how many cores are on the same physical compute node. +NbrOfPhysicalNodes = GETINT('NbrOfPhysicalNodes') +IF(NbrOfPhysicalNodes.LE.0) MemoryMonitor = .FALSE. +#endif /*! (CORE_SPLIT==0)*/ + ! Split the node communicator (shared memory) from the global communicator on physical processor or node level #if (CORE_SPLIT==1) CALL MPI_COMM_SPLIT(MPI_COMM_WORLD,myRank,0,MPI_COMM_SHARED,iError) diff --git a/src/mpi/mpi_shared_vars.f90 b/src/mpi/mpi_shared_vars.f90 index 89dc9e87f..980f4287e 100644 --- a/src/mpi/mpi_shared_vars.f90 +++ b/src/mpi/mpi_shared_vars.f90 @@ -37,6 +37,11 @@ MODULE MOD_MPI_Shared_Vars INTEGER :: myLeaderGroupRank !> Rank of compute-node root in compute-node-root comm INTEGER :: nComputeNodeProcessors !> Number of procs on current compute-node INTEGER :: nLeaderGroupProcs !> Number of nodes +#if ! (CORE_SPLIT==0) +! When core-level splitting is used, it is not clear how many cores are on the same physical compute node. +INTEGER :: NbrOfPhysicalNodes !> Number of physical nodes (as opposed to virtual nodes) +#endif /*! (CORE_SPLIT==0)*/ +LOGICAL :: MemoryMonitor !> Flag for turning RAM monitoring ON/OFF. Used for the detection of RAM overflows (e.g. due to memory leaks) INTEGER :: nProcessors_Global !> Number of total procs INTEGER :: MPI_COMM_SHARED !> Communicator on current compute-node INTEGER :: MPI_COMM_LEADERS_SHARED !> Communicator compute-node roots (my_rank_shared=0) From a4097d107a3f8c8b9445763faca13759f7a3376f Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Mon, 28 Nov 2022 01:40:55 +0100 Subject: [PATCH 28/36] Fixed calculation of kinetic energy (CalcKineticEnergy=T) when using PMLs or dielectric regions. --- .../analyze/particle_analyze_tools.f90 | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/particles/analyze/particle_analyze_tools.f90 b/src/particles/analyze/particle_analyze_tools.f90 index 5a584e993..1dbebd437 100644 --- a/src/particles/analyze/particle_analyze_tools.f90 +++ b/src/particles/analyze/particle_analyze_tools.f90 @@ -896,14 +896,15 @@ PPURE SUBROUTINE CalcKineticEnergy(Ekin) USE MOD_Globals USE MOD_Preproc USE MOD_Globals_Vars ,ONLY: c2, c2_inv, RelativisticLimit -USE MOD_Particle_Vars ,ONLY: PartState, PartSpecies, Species, PDM +USE MOD_Particle_Vars ,ONLY: PartState, PartSpecies, Species, PDM, PEM USE MOD_PARTICLE_Vars ,ONLY: usevMPF USE MOD_Particle_Analyze_Vars ,ONLY: nSpecAnalyze USE MOD_part_tools ,ONLY: GetParticleWeight USE MOD_DSMC_Vars ,ONLY: RadialWeighting #if !(USE_HDG) -USE MOD_PML_Vars ,ONLY: DoPML,xyzPhysicalMinMax +USE MOD_PML_Vars ,ONLY: DoPML,isPMLElem #endif /*USE_HDG*/ +USE MOD_Dielectric_Vars ,ONLY: DoDielectric,isDielectricElem,DielectricNoParticles ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- @@ -913,7 +914,7 @@ PPURE SUBROUTINE CalcKineticEnergy(Ekin) REAL,INTENT(OUT) :: Ekin(nSpecAnalyze) !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -INTEGER :: i +INTEGER :: i,ElemID REAL(KIND=8) :: partV2, GammaFac REAL :: Ekin_loc !=================================================================================================================================== @@ -921,15 +922,17 @@ PPURE SUBROUTINE CalcKineticEnergy(Ekin) IF (nSpecAnalyze.GT.1) THEN DO i=1,PDM%ParticleVecLength IF (PDM%ParticleInside(i)) THEN + ElemID = PEM%LocalElemID(i) #if !(USE_HDG) IF(DoPML)THEN - IF (PartState(1,i) .GE. xyzPhysicalMinMax(1) .AND. PartState(1,i) .LE. xyzPhysicalMinMax(2) .AND. & - PartState(2,i) .GE. xyzPhysicalMinMax(3) .AND. PartState(2,i) .LE. xyzPhysicalMinMax(4) .AND. & - PartState(3,i) .GE. xyzPhysicalMinMax(5) .AND. PartState(3,i) .LE. xyzPhysicalMinMax(6)) THEN - CYCLE - END IF + IF(isPMLElem(ElemID)) CYCLE ENDIF #endif /*USE_HDG*/ + IF(DoDielectric)THEN + IF(DielectricNoParticles)THEN + IF(isDielectricElem(ElemID)) CYCLE + END IF ! DielectricNoParticles + ENDIF partV2 = DOTPRODUCT(PartState(4:6,i)) IF ( partV2 .LT. RelativisticLimit) THEN ! |v| < 1000000 when speed of light is 299792458 Ekin_loc = 0.5 * Species(PartSpecies(i))%MassIC * partV2 @@ -961,15 +964,17 @@ PPURE SUBROUTINE CalcKineticEnergy(Ekin) ELSE ! nSpecAnalyze = 1 : only 1 species DO i=1,PDM%ParticleVecLength IF (PDM%ParticleInside(i)) THEN + ElemID = PEM%LocalElemID(i) #if !(USE_HDG) IF(DoPML)THEN - IF (PartState(1,i) .GE. xyzPhysicalMinMax(1) .AND. PartState(1,i) .LE. xyzPhysicalMinMax(2) .AND. & - PartState(2,i) .GE. xyzPhysicalMinMax(3) .AND. PartState(2,i) .LE. xyzPhysicalMinMax(4) .AND. & - PartState(3,i) .GE. xyzPhysicalMinMax(5) .AND. PartState(3,i) .LE. xyzPhysicalMinMax(6)) THEN - CYCLE - END IF + IF(isPMLElem(ElemID)) CYCLE ENDIF #endif /*USE_HDG*/ + IF(DoDielectric)THEN + IF(DielectricNoParticles)THEN + IF(isDielectricElem(ElemID)) CYCLE + END IF ! DielectricNoParticles + ENDIF partV2 = DOTPRODUCT(PartState(4:6,i)) IF ( partV2 .LT. RelativisticLimit) THEN ! |v| < 1000000 when speed of light is 299792458 Ekin_loc = 0.5 * Species(PartSpecies(i))%MassIC * partV2 @@ -1004,14 +1009,15 @@ PPURE SUBROUTINE CalcKineticEnergyAndMaximum(Ekin,EkinMax) USE MOD_Globals USE MOD_Preproc USE MOD_Globals_Vars ,ONLY: c2, c2_inv, RelativisticLimit -USE MOD_Particle_Vars ,ONLY: PartState, PartSpecies, Species, PDM, nSpecies +USE MOD_Particle_Vars ,ONLY: PartState, PartSpecies, Species, PDM, nSpecies, PEM USE MOD_PARTICLE_Vars ,ONLY: usevMPF USE MOD_Particle_Analyze_Vars ,ONLY: nSpecAnalyze,LaserInteractionEkinMaxRadius,LaserInteractionEkinMaxZPosMin USE MOD_part_tools ,ONLY: GetParticleWeight USE MOD_DSMC_Vars ,ONLY: RadialWeighting #if !(USE_HDG) -USE MOD_PML_Vars ,ONLY: DoPML,xyzPhysicalMinMax +USE MOD_PML_Vars ,ONLY: DoPML,isPMLElem #endif /*USE_HDG*/ +USE MOD_Dielectric_Vars ,ONLY: DoDielectric,isDielectricElem,DielectricNoParticles ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------- @@ -1022,7 +1028,7 @@ PPURE SUBROUTINE CalcKineticEnergyAndMaximum(Ekin,EkinMax) REAL,INTENT(OUT) :: EkinMax(nSpecies) !----------------------------------------------------------------------------------------------------------------------------------- ! LOCAL VARIABLES -INTEGER :: i +INTEGER :: i,ElemID REAL(KIND=8) :: partV2, GammaFac REAL :: Ekin_loc !=================================================================================================================================== @@ -1033,15 +1039,17 @@ PPURE SUBROUTINE CalcKineticEnergyAndMaximum(Ekin,EkinMax) IF (nSpecAnalyze.GT.1) THEN DO i=1,PDM%ParticleVecLength IF (PDM%ParticleInside(i)) THEN + ElemID = PEM%LocalElemID(i) #if !(USE_HDG) IF(DoPML)THEN - IF (PartState(1,i) .GE. xyzPhysicalMinMax(1) .AND. PartState(1,i) .LE. xyzPhysicalMinMax(2) .AND. & - PartState(2,i) .GE. xyzPhysicalMinMax(3) .AND. PartState(2,i) .LE. xyzPhysicalMinMax(4) .AND. & - PartState(3,i) .GE. xyzPhysicalMinMax(5) .AND. PartState(3,i) .LE. xyzPhysicalMinMax(6)) THEN - CYCLE - END IF + IF(isPMLElem(ElemID)) CYCLE ENDIF #endif /*USE_HDG*/ + IF(DoDielectric)THEN + IF(DielectricNoParticles)THEN + IF(isDielectricElem(ElemID)) CYCLE + END IF ! DielectricNoParticles + ENDIF partV2 = DOTPRODUCT(PartState(4:6,i)) IF ( partV2 .LT. RelativisticLimit) THEN ! |v| < 1000000 when speed of light is 299792458 Ekin_loc = 0.5 * Species(PartSpecies(i))%MassIC * partV2 @@ -1076,15 +1084,17 @@ PPURE SUBROUTINE CalcKineticEnergyAndMaximum(Ekin,EkinMax) ELSE ! nSpecAnalyze = 1 : only 1 species DO i=1,PDM%ParticleVecLength IF (PDM%ParticleInside(i)) THEN + ElemID = PEM%LocalElemID(i) #if !(USE_HDG) IF(DoPML)THEN - IF (PartState(1,i) .GE. xyzPhysicalMinMax(1) .AND. PartState(1,i) .LE. xyzPhysicalMinMax(2) .AND. & - PartState(2,i) .GE. xyzPhysicalMinMax(3) .AND. PartState(2,i) .LE. xyzPhysicalMinMax(4) .AND. & - PartState(3,i) .GE. xyzPhysicalMinMax(5) .AND. PartState(3,i) .LE. xyzPhysicalMinMax(6)) THEN - CYCLE - END IF + IF(isPMLElem(ElemID)) CYCLE ENDIF #endif /*USE_HDG*/ + IF(DoDielectric)THEN + IF(DielectricNoParticles)THEN + IF(isDielectricElem(ElemID)) CYCLE + END IF ! DielectricNoParticles + ENDIF partV2 = DOTPRODUCT(PartState(4:6,i)) IF ( partV2 .LT. RelativisticLimit) THEN ! |v| < 1000000 when speed of light is 299792458 Ekin_loc = 0.5 * Species(PartSpecies(i))%MassIC * partV2 From a67e97f0077601da45a7aec82b76e4d29de97c6b Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Mon, 28 Nov 2022 21:55:15 +0100 Subject: [PATCH 29/36] Adjusted abort message when switching from UseDSMC=F to T. --- src/particles/restart/particle_readin.f90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/particles/restart/particle_readin.f90 b/src/particles/restart/particle_readin.f90 index 751d54462..d94c38ba6 100644 --- a/src/particles/restart/particle_readin.f90 +++ b/src/particles/restart/particle_readin.f90 @@ -126,6 +126,7 @@ SUBROUTINE ParticleReadin() INTEGER :: MPI_LENGTH(1),MPI_TYPE(1),MPI_STRUCT INTEGER(KIND=MPI_ADDRESS_KIND) :: MPI_DISPLACEMENT(1) #endif /*USE_LOADBALANCE*/ +CHARACTER(LEN=32) :: hilf !=================================================================================================================================== FirstElemInd = offsetElem+1 @@ -611,11 +612,13 @@ SUBROUTINE ParticleReadin() DO iVar=1,PartDataSize IF (.NOT.readVarFromState(iVar)) THEN IF (TRIM(StrVarNames(iVar)).EQ.'Vibrational' .OR. TRIM(StrVarNames(iVar)).EQ.'Rotational') THEN - SWRITE(*,*) 'WARNING: The following VarNamesParticles will be set to zero: '//TRIM(StrVarNames(iVar)) + WRITE(UNIT=hilf,FMT='(I0)') iVar + SWRITE(*,*) 'WARNING: The following VarNamesParticles(iVar='//TRIM(hilf)//') will be set to zero: '//TRIM(StrVarNames(iVar)) ELSE IF(TRIM(StrVarNames(iVar)).EQ.'MPF') THEN SWRITE(*,*) 'WARNING: The particle weighting factor will be initialized with the given global weighting factor!' ELSE - CALL Abort(__STAMP__,"not associated VarNamesParticles to be reset!") + CALL Abort(__STAMP__,"not associated VarNamesParticles to be reset! StrVarNames(iVar)="//TRIM(StrVarNames(iVar))//& + '. Note that initializing electronic DOF and vibrational molecular species with zero ist not imeplemted.') END IF ! TRIM(StrVarNames(iVar)).EQ.'Vibrational' .OR. TRIM(StrVarNames(iVar)).EQ.'Rotational' END IF ! .NOT.readVarFromState(iVar) END DO ! iVar=1,PartDataSize From 890909f17f73e1a37beb00c4f46fe169025a6c15 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Mon, 5 Dec 2022 23:53:25 +0100 Subject: [PATCH 30/36] Fixed 2D and 3D interpolation of external magnetic field or density/temperature/velocity data from .h5 by considering that coordinates may be equal to the upper boundary of the data interval. Fixes out-of-bounds access to data arrays. --- src/globals/globals_vars.f90 | 2 +- src/particles/particle_tools.f90 | 33 +++++++----- .../interpolation/pic_interpolation_tools.f90 | 51 +++++++++++++------ 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/globals/globals_vars.f90 b/src/globals/globals_vars.f90 index b2600d99d..994a9d480 100644 --- a/src/globals/globals_vars.f90 +++ b/src/globals/globals_vars.f90 @@ -23,7 +23,7 @@ MODULE MOD_Globals_Vars !----------------------------------------------------------------------------------------------------------------------------------- CHARACTER(LEN=6),PARAMETER :: ProgramName = 'PICLas' !> name of this program INTEGER,PARAMETER :: MajorVersion = 2 !> FileVersion number saved in each hdf5 file with hdf5 header -INTEGER,PARAMETER :: MinorVersion = 8 !> FileVersion number saved in each hdf5 file with hdf5 header +INTEGER,PARAMETER :: MinorVersion = 9 !> FileVersion number saved in each hdf5 file with hdf5 header INTEGER,PARAMETER :: PatchVersion = 0 !> FileVersion number saved in each hdf5 file with hdf5 header REAL,PARAMETER :: FileVersion = REAL(MajorVersion,8)+REAL(MinorVersion,8)/10.+REAL(PatchVersion,8)/100. !> FileVersion !> number saved in each hdf5 file with hdf5 header diff --git a/src/particles/particle_tools.f90 b/src/particles/particle_tools.f90 index 4dccd105e..3651b1803 100644 --- a/src/particles/particle_tools.f90 +++ b/src/particles/particle_tools.f90 @@ -1184,10 +1184,7 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(iSpec,iInit,Pos,dimLower,dimUpp z => Pos(3) ,& EmissionDistribution => Species(iSpec)%Init(iInit)%EmissionDistribution& ) - r = SQRT(x**2+y**2) - iPos = INT((r-EmissionDistribution(1,1))/EmissionDistributionDelta(1)) + 1 - jPos = INT((z-EmissionDistribution(2,1))/EmissionDistributionDelta(2)) + 1 - + r = SQRT(x*x + y*y) IF(r.GT.EmissionDistributionMax(1))THEN InterpolateEmissionDistribution2D = 0. @@ -1198,14 +1195,26 @@ PPURE FUNCTION InterpolateEmissionDistribution2D(iSpec,iInit,Pos,dimLower,dimUpp ELSEIF(z.LT.EmissionDistributionMin(2))THEN InterpolateEmissionDistribution2D = 0. ELSE - ! 1.1 - idx1 = (iPos-1)*EmissionDistributionNum(1) + jPos - ! 2.1 - idx2 = (iPos-1)*EmissionDistributionNum(1) + jPos + 1 - ! 1.2 - idx3 = iPos*EmissionDistributionNum(1) + jPos - ! 2.2 - idx4 = iPos*EmissionDistributionNum(1) + jPos + 1 + + ! Get index in r and z + iPos = INT((r-EmissionDistribution(1,1))/EmissionDistributionDelta(1)) + 1 ! dr = EmissionDistributionDelta(1) + jPos = INT((z-EmissionDistribution(2,1))/EmissionDistributionDelta(2)) + 1 ! dz = EmissionDistributionDelta(2) + ! Catch problem when r or z are exactly at the upper boundary and INT() does not round to the lower integer (do not add +1 in + ! this case) + iPos = MIN(iPos, EmissionDistributionNum(2) - 1 ) + jPos = MIN(jPos, EmissionDistributionNum(1) - 1 ) + + ! Shift all points by Nz = EmissionDistributionNum(1) + ASSOCIATE( Nz => EmissionDistributionNum(1) ) + ! 1.1 + idx1 = (iPos-1)*Nz + jPos + ! 2.1 + idx2 = (iPos-1)*Nz + jPos + 1 + ! 1.2 + idx3 = iPos*Nz + jPos + ! 2.2 + idx4 = iPos*Nz + jPos + 1 + END ASSOCIATE ! Interpolate delta = EmissionDistributionDelta(1)*EmissionDistributionDelta(2) diff --git a/src/particles/pic/interpolation/pic_interpolation_tools.f90 b/src/particles/pic/interpolation/pic_interpolation_tools.f90 index 4baafee91..c8f52d85c 100644 --- a/src/particles/pic/interpolation/pic_interpolation_tools.f90 +++ b/src/particles/pic/interpolation/pic_interpolation_tools.f90 @@ -501,10 +501,7 @@ PPURE FUNCTION InterpolateVariableExternalField2D(Pos) y => Pos(2) ,& z => Pos(3) & ) - r = SQRT(x**2+y**2) - iPos = INT((r-VariableExternalField(1,1))/DeltaExternalField(1)) + 1 - jPos = INT((z-VariableExternalField(2,1))/DeltaExternalField(2)) + 1 - + r = SQRT(x*x + y*y) IF(r.GT.VariableExternalFieldMax(1))THEN InterpolateVariableExternalField2D = 0. @@ -515,14 +512,28 @@ PPURE FUNCTION InterpolateVariableExternalField2D(Pos) ELSEIF(z.LT.VariableExternalFieldMin(2))THEN InterpolateVariableExternalField2D = 0. ELSE - ! 1.1 - idx1 = (iPos-1)*VariableExternalFieldN(1) + jPos - ! 2.1 - idx2 = (iPos-1)*VariableExternalFieldN(1) + jPos + 1 - ! 1.2 - idx3 = iPos*VariableExternalFieldN(1) + jPos - ! 2.2 - idx4 = iPos*VariableExternalFieldN(1) + jPos + 1 + + ! Get index in r and z + iPos = INT((r-VariableExternalField(1,1))/DeltaExternalField(1)) + 1 ! dr = DeltaExternalField(1) + jPos = INT((z-VariableExternalField(2,1))/DeltaExternalField(2)) + 1 ! dz = DeltaExternalField(2) + + ! Catch problem when r or z are exactly at the upper boundary and INT() does not round to the lower integer (do not add +1 in + ! this case) + iPos = MIN(iPos, VariableExternalFieldN(2) - 1 ) + jPos = MIN(jPos, VariableExternalFieldN(1) - 1 ) + + + ! Shift all points by Nz = EmissionDistributionNum(1) + ASSOCIATE( Nz => VariableExternalFieldN(1) ) + ! 1.1 + idx1 = (iPos-1)*Nz + jPos + ! 2.1 + idx2 = (iPos-1)*Nz + jPos + 1 + ! 1.2 + idx3 = iPos*Nz + jPos + ! 2.2 + idx4 = iPos*Nz + jPos + 1 + END ASSOCIATE ! Interpolate delta = DeltaExternalField(1)*DeltaExternalField(2) @@ -604,10 +615,6 @@ PPURE FUNCTION InterpolateVariableExternalField3D(Pos) Ny => VariableExternalFieldN(2) ,& Nz => VariableExternalFieldN(3) & ) - iPos = INT((x-VariableExternalField(1,1))/DeltaExternalField(1)) ! 0 to Nx-1 - jPos = INT((y-VariableExternalField(2,1))/DeltaExternalField(2)) ! 0 to Ny-1 - kPos = INT((z-VariableExternalField(3,1))/DeltaExternalField(3)) ! 0 to Nz-1 - Nxy = Nx*Ny ! Magnetic field outside of interpolation domain results in B=0 IF(x.GT.VariableExternalFieldMax(1))THEN @@ -623,6 +630,18 @@ PPURE FUNCTION InterpolateVariableExternalField3D(Pos) ELSEIF(z.LT.VariableExternalFieldMin(3))THEN InterpolateVariableExternalField3D = 0. ELSE + + ! Get index in x, y and z + iPos = INT((x-VariableExternalField(1,1))/DeltaExternalField(1)) ! 0 to Nx-1 + jPos = INT((y-VariableExternalField(2,1))/DeltaExternalField(2)) ! 0 to Ny-1 + kPos = INT((z-VariableExternalField(3,1))/DeltaExternalField(3)) ! 0 to Nz-1 + ! Catch problem when coordinates are exactly at the upper boundary and INT() does not round to the lower integer + ! e.g. when x.EQ.VariableExternalFieldMax(1) or y.EQ.VariableExternalFieldMax(2) or z.EQ.VariableExternalFieldMax(3) + IF(iPos.EQ.Nx) iPos = Nx-1 + IF(jPos.EQ.Ny) jPos = Ny-1 + IF(kPos.EQ.Nz) kPos = Nz-1 + Nxy = Nx*Ny + ! Get corner node indices ! 1.1.1 idx1 = iPos + jPos*Ny + kPos*Nxy + 1 From 3615ec1d5234af50de35a518a596e2aecb04f3d2 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 6 Dec 2022 00:28:17 +0100 Subject: [PATCH 31/36] Added new variable to MPI Wait measurement: MPI_REDUCE when collecting the information on the RAM usage. --- src/loadbalance/loaddistribution.f90 | 15 +++ src/mpi/mpi.f90 | 142 ++++++++++++++------------- src/mpi/mpi_vars.f90 | 2 + src/piclas.f90 | 6 +- src/piclas.h | 2 +- 5 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/loadbalance/loaddistribution.f90 b/src/loadbalance/loaddistribution.f90 index 24c1f98c5..88b3cf7cb 100644 --- a/src/loadbalance/loaddistribution.f90 +++ b/src/loadbalance/loaddistribution.f90 @@ -1244,6 +1244,9 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) #endif /*! (CORE_SPLIT==0)*/ #endif /*USE_MPI*/ USE MOD_StringTools ,ONLY: set_formatting,clear_formatting +#if defined(MEASURE_MPI_WAIT) +USE MOD_MPI_Vars ,ONLY: MPIW8TimeMM,MPIW8CountMM +#endif /*defined(MEASURE_MPI_WAIT)*/ ! IMPLICIT VARIABLE HANDLING IMPLICIT NONE !----------------------------------------------------------------------------------------------------------------------------------! @@ -1298,6 +1301,10 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) REAL :: NodeMemoryUsed ! Sum of used memory across one compute node #endif /*USE_MPI*/ REAL :: MemUsagePercent +#if defined(MEASURE_MPI_WAIT) +INTEGER(KIND=8) :: CounterStart,CounterEnd +REAL(KIND=8) :: Rate +#endif /*defined(MEASURE_MPI_WAIT)*/ !=================================================================================================================================== ! Get process memory info @@ -1305,6 +1312,9 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) ! only CN roots communicate available and total memory info (count once per node) #if USE_MPI +#if defined(MEASURE_MPI_WAIT) +CALL SYSTEM_CLOCK(count=CounterStart) +#endif /*defined(MEASURE_MPI_WAIT)*/ IF(nProcessors.GT.1)THEN ! Collect data on node roots ProcMemoryUsed = memory(1) @@ -1324,6 +1334,11 @@ SUBROUTINE WriteElemTimeStatistics(WriteHeader,time_opt,iter_opt) END IF ! myLeaderGroupRank.EQ.0 END IF ! myComputeNodeRank.EQ.0 END IF ! nProcessors.EQ.1 +#if defined(MEASURE_MPI_WAIT) +CALL SYSTEM_CLOCK(count=CounterEnd, count_rate=Rate) +MPIW8TimeMM = MPIW8TimeMM + REAL(CounterEnd-CounterStart,8)/Rate +MPIW8CountMM = MPIW8CountMM + 1_8 +#endif /*defined(MEASURE_MPI_WAIT)*/ #endif /*USE_MPI*/ ! -------------------------------------------------- diff --git a/src/mpi/mpi.f90 b/src/mpi/mpi.f90 index 12710707e..007abff97 100644 --- a/src/mpi/mpi.f90 +++ b/src/mpi/mpi.f90 @@ -456,7 +456,7 @@ SUBROUTINE OutputMPIW8Time() USE MOD_Globals USE MOD_MPI_Vars ,ONLY: MPIW8TimeGlobal , MPIW8TimeProc , MPIW8TimeField , MPIW8Time , MPIW8TimeBaS USE MOD_MPI_Vars ,ONLY: MPIW8CountGlobal , MPIW8CountProc , MPIW8CountField , MPIW8Count , MPIW8CountBaS -USE MOD_MPI_Vars ,ONLY: MPIW8TimeSim +USE MOD_MPI_Vars ,ONLY: MPIW8TimeSim,MPIW8TimeMM, MPIW8CountMM USE MOD_StringTools ,ONLY: INTTOSTR #if defined(PARTICLES) USE MOD_Particle_MPI_Vars ,ONLY: MPIW8TimePart,MPIW8CountPart @@ -480,7 +480,9 @@ SUBROUTINE OutputMPIW8Time() 'nProcessors' , & 'WallTimeSim' , & 'Barrier-and-Sync' , & - 'Barrier-and-Sync-Counter' & + 'Barrier-and-Sync-Counter' , & + 'RAM-Measure-Reduce' , & + 'RAM-Measure-Reduce-Counter' & #if USE_HDG ,'HDG-SendLambda' , & ! (1) 'HDG-SendLambda-Counter' , & ! (1) @@ -527,11 +529,13 @@ SUBROUTINE OutputMPIW8Time() !=================================================================================================================================== MPIW8Time( 1:1) = MPIW8TimeBaS MPIW8Count( 1:1) = MPIW8CountBaS -MPIW8Time( 2:MPIW8SIZEFIELD+1) = MPIW8TimeField -MPIW8Count( 2:MPIW8SIZEFIELD+1) = MPIW8CountField +MPIW8Time( 2:2) = MPIW8TimeMM +MPIW8Count( 2:2) = MPIW8CountMM +MPIW8Time( 3:MPIW8SIZEFIELD+2) = MPIW8TimeField +MPIW8Count( 3:MPIW8SIZEFIELD+2) = MPIW8CountField #if defined(PARTICLES) -MPIW8Time( MPIW8SIZEFIELD+2:MPIW8SIZEFIELD+MPIW8SIZEPART+1) = MPIW8TimePart -MPIW8Count(MPIW8SIZEFIELD+2:MPIW8SIZEFIELD+MPIW8SIZEPART+1) = MPIW8CountPart +MPIW8Time( MPIW8SIZEFIELD+3:MPIW8SIZEFIELD+MPIW8SIZEPART+2) = MPIW8TimePart +MPIW8Count(MPIW8SIZEFIELD+3:MPIW8SIZEFIELD+MPIW8SIZEPART+2) = MPIW8CountPart #endif /*defined(PARTICLES)*/ ! Collect and output measured MPI_WAIT() times @@ -596,29 +600,31 @@ SUBROUTINE OutputMPIW8Time() delimiter,MPIW8TimeSimeGlobal ,& ! 'WallTimeSim' delimiter,MPIW8TimeGlobal(1) ,& ! 'Barrier-and-Sync' delimiter,REAL(MPIW8CountGlobal(1)) ,& ! 'Barrier-and-Sync-Counter' - delimiter,MPIW8TimeGlobal(2) ,& ! (1) 'HDG-SendLambda' or 'DGSEM-Send' - delimiter,REAL(MPIW8CountGlobal(2)) ,& ! (1) 'HDG-SendLambda-Counter' or 'DGSEM-Send-Counter' - delimiter,MPIW8TimeGlobal(3) ,& ! (2) 'HDG-ReceiveLambda' or 'DGSEM-Receive' - delimiter,REAL(MPIW8CountGlobal(3)) & ! (2) 'HDG-ReceiveLambda-Counter' or 'DGSEM-Receive-Counter' + delimiter,MPIW8TimeGlobal(2) ,& ! 'RAM-Measure-Reduce' + delimiter,REAL(MPIW8CountGlobal(2)) ,& ! 'RAM-Measure-Reduce-Counter' + delimiter,MPIW8TimeGlobal(3) ,& ! (1) 'HDG-SendLambda' or 'DGSEM-Send' + delimiter,REAL(MPIW8CountGlobal(3)) ,& ! (1) 'HDG-SendLambda-Counter' or 'DGSEM-Send-Counter' + delimiter,MPIW8TimeGlobal(4) ,& ! (2) 'HDG-ReceiveLambda' or 'DGSEM-Receive' + delimiter,REAL(MPIW8CountGlobal(4)) & ! (2) 'HDG-ReceiveLambda-Counter' or 'DGSEM-Receive-Counter' #if USE_HDG - ,delimiter,MPIW8TimeGlobal(4) ,& ! (3) 'HDG-Broadcast' - delimiter,REAL(MPIW8CountGlobal(4)) ,& ! (3) 'HDG-Broadcast-Counter' - delimiter,MPIW8TimeGlobal(5) ,& ! (4) 'HDG-Allreduce' - delimiter,REAL(MPIW8CountGlobal(5)) & ! (4) 'HDG-Allreduce-Counter' + ,delimiter,MPIW8TimeGlobal(5) ,& ! (3) 'HDG-Broadcast' + delimiter,REAL(MPIW8CountGlobal(5)) ,& ! (3) 'HDG-Broadcast-Counter' + delimiter,MPIW8TimeGlobal(6) ,& ! (4) 'HDG-Allreduce' + delimiter,REAL(MPIW8CountGlobal(6)) & ! (4) 'HDG-Allreduce-Counter' #endif /*USE_HDG*/ #if defined(PARTICLES) - ,delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+1) ,& ! (1) 'SendNbrOfParticles' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+1)) ,& ! (1) 'SendNbrOfParticles-Counter' - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+2) ,& ! (2) 'RecvNbrOfParticles' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+2)) ,& ! (2) 'RecvNbrOfParticles-Counter' - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+3) ,& ! (3) 'SendParticles' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+3)) ,& ! (3) 'SendParticles-Counter' - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+4) ,& ! (4) 'RecvParticles' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+4)) ,& ! (4) 'RecvParticles-Counter' - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+5) ,& ! (5) 'EmissionParticles' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+5)) ,& ! (5) 'EmissionParticles-Counter' - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+6) ,& ! (6) 'PIC-depo-Wait' - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+6)) & ! (6) 'PIC-depo-Wait-Counter' + ,delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+1) ,& ! (1) 'SendNbrOfParticles' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+1)) ,& ! (1) 'SendNbrOfParticles-Counter' + delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+2) ,& ! (2) 'RecvNbrOfParticles' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+2)) ,& ! (2) 'RecvNbrOfParticles-Counter' + delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+3) ,& ! (3) 'SendParticles' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+3)) ,& ! (3) 'SendParticles-Counter' + delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+4) ,& ! (4) 'RecvParticles' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+4)) ,& ! (4) 'RecvParticles-Counter' + delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+5) ,& ! (5) 'EmissionParticles' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+5)) ,& ! (5) 'EmissionParticles-Counter' + delimiter,MPIW8TimeGlobal( MPIW8SIZEFIELD+2+6) ,& ! (6) 'PIC-depo-Wait' + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+6)) & ! (6) 'PIC-depo-Wait-Counter' #endif /*defined(PARTICLES)*/ ; ! this is required for terminating the "&" when particles=off WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the data line @@ -666,31 +672,33 @@ SUBROUTINE OutputMPIW8Time() WRITE(tmpStr2,formatStr) & " ",REAL(nProcessors) ,& delimiter,100. ,& ! MPIW8TimeSim*nProcessors / TotalSimTime - delimiter,MPIW8TimeGlobal(1)/TotalSimTime ,& + delimiter, MPIW8TimeGlobal(1) /TotalSimTime ,& delimiter,REAL(MPIW8CountGlobal(1))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(2)/TotalSimTime ,& + delimiter, MPIW8TimeGlobal(2) /TotalSimTime ,& delimiter,REAL(MPIW8CountGlobal(2))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(3)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(3))/TotalCounter & + delimiter, MPIW8TimeGlobal(3) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(3))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(4) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(4))/TotalCounter & #if USE_HDG - ,delimiter,MPIW8TimeGlobal(4)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(4))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(5)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(5))/TotalCounter & + ,delimiter, MPIW8TimeGlobal(5) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(5))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(6) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(6))/TotalCounter & #endif /*USE_HDG*/ #if defined(PARTICLES) - ,delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+1)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+1))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+2)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+2))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+3)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+3))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+4)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+4))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+5)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+5))/TotalCounter ,& - delimiter,MPIW8TimeGlobal(MPIW8SIZEFIELD+1+6)/TotalSimTime ,& - delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+1+6))/TotalCounter & + ,delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+1) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+1))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+2) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+2))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+3) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+3))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+4) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+4))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+5) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+5))/TotalCounter ,& + delimiter, MPIW8TimeGlobal(MPIW8SIZEFIELD+2+6) /TotalSimTime ,& + delimiter,REAL(MPIW8CountGlobal(MPIW8SIZEFIELD+2+6))/TotalCounter & #endif /*defined(PARTICLES)*/ ; ! this is required for terminating the "&" when particles=off WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the data line @@ -737,31 +745,33 @@ SUBROUTINE OutputMPIW8Time() WRITE(tmpStr2,formatStr) & " ",REAL(i) ,& delimiter,MPIW8TimeSim ,& - delimiter,MPIW8TimeProc(i*MPIW8SIZE+1) ,& + delimiter, MPIW8TimeProc(i*MPIW8SIZE+1) ,& delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+1)) ,& - delimiter,MPIW8TimeProc(i*MPIW8SIZE+2) ,& + delimiter, MPIW8TimeProc(i*MPIW8SIZE+2) ,& delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+2)) ,& - delimiter,MPIW8TimeProc(i*MPIW8SIZE+3) ,& - delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+3)) & + delimiter, MPIW8TimeProc(i*MPIW8SIZE+2) ,& + delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+2)) ,& + delimiter, MPIW8TimeProc(i*MPIW8SIZE+4) ,& + delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+4)) & #if USE_HDG - ,delimiter,MPIW8TimeProc(i*MPIW8SIZE+4) ,& - delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+4)) ,& - delimiter,MPIW8TimeProc(i*MPIW8SIZE+5) ,& - delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+5)) & + ,delimiter, MPIW8TimeProc(i*MPIW8SIZE+5) ,& + delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+5)) ,& + delimiter, MPIW8TimeProc(i*MPIW8SIZE+6) ,& + delimiter,REAL(MPIW8CountProc(i*MPIW8SIZE+6)) & #endif /*USE_HDG*/ #if defined(PARTICLES) - ,delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+1) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+1)) ,& - delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+2) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+2)) ,& - delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+3) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+3)) ,& - delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+4) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+4)) ,& - delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+5) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+5)) ,& - delimiter,MPIW8TimeProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+6) ,& - delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+1+i*MPIW8SIZE+6)) & + ,delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+1) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+1)) ,& + delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+2) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+2)) ,& + delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+3) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+3)) ,& + delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+4) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+4)) ,& + delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+5) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+5)) ,& + delimiter, MPIW8TimeProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+6) ,& + delimiter,REAL(MPIW8CountProc(MPIW8SIZEFIELD+2+i*MPIW8SIZE+6)) & #endif /*defined(PARTICLES)*/ ; ! this is required for terminating the "&" when particles=off WRITE(ioUnit,'(A)')TRIM(ADJUSTL(tmpStr2)) ! clip away the front and rear white spaces of the data line diff --git a/src/mpi/mpi_vars.f90 b/src/mpi/mpi_vars.f90 index 61653ebf9..038ec10be 100644 --- a/src/mpi/mpi_vars.f90 +++ b/src/mpi/mpi_vars.f90 @@ -50,12 +50,14 @@ MODULE MOD_MPI_Vars ! Elapsed times REAL(KIND=8) :: MPIW8TimeSim !< measure global time in the simulation as reference REAL(KIND=8) :: MPIW8TimeBaS !< measure time on each proc it is in BARRIER_AND_SYNC +REAL(KIND=8) :: MPIW8TimeMM !< measure time on each proc it is in REDUCE for RAM measurement REAL(KIND=8) :: MPIW8TimeField(MPIW8SIZEFIELD) !< measure time on each proc it is in MPI_WAIT() during the field solver REAL(KIND=8) :: MPIW8Time(MPIW8SIZE) !< measure time on each proc it is in MPI_WAIT() REAL(KIND=8) :: MPIW8TimeGlobal(MPIW8SIZE) !< measure time on each proc it is in MPI_WAIT() global over all ranks REAL(KIND=8),ALLOCATABLE :: MPIW8TimeProc(:) !< measure time on each proc it is in MPI_WAIT() proc local output ! Counter INTEGER(KIND=8) :: MPIW8CountBaS !< count the number of measurements on each proc it is in BARRIER_AND_SYNC +INTEGER(KIND=8) :: MPIW8CountMM !< count the number of measurements on each proc it is in REDUCE for RAM measurement INTEGER(KIND=8) :: MPIW8CountField(MPIW8SIZEFIELD) !< count the number of measurements on each proc it is in MPI_WAIT() during the field solver INTEGER(KIND=8) :: MPIW8Count(MPIW8SIZE) !< count the number of measurements on each proc it is in MPI_WAIT() INTEGER(KIND=8) :: MPIW8CountGlobal(MPIW8SIZE) !< count the number of measurements on each proc it is in MPI_WAIT() global over all ranks diff --git a/src/piclas.f90 b/src/piclas.f90 index 8d7b1d1cf..4f21d4847 100644 --- a/src/piclas.f90 +++ b/src/piclas.f90 @@ -23,8 +23,8 @@ PROGRAM Piclas USE MOD_TimeDisc ,ONLY: TimeDisc #if defined(MEASURE_MPI_WAIT) USE MOD_MPI ,ONLY: OutputMPIW8Time -USE MOD_MPI_Vars ,ONLY: MPIW8Time,MPIW8TimeSim,MPIW8TimeField,MPIW8TimeBaS -USE MOD_MPI_Vars ,ONLY: MPIW8Count,MPIW8CountField,MPIW8CountBaS +USE MOD_MPI_Vars ,ONLY: MPIW8Time,MPIW8TimeSim,MPIW8TimeField,MPIW8TimeBaS,MPIW8TimeMM +USE MOD_MPI_Vars ,ONLY: MPIW8Count,MPIW8CountField,MPIW8CountBaS,MPIW8CountMM #if defined(PARTICLES) USE MOD_Particle_MPI_Vars ,ONLY: MPIW8TimePart,MPIW8CountPart #endif /*defined(PARTICLES)*/ @@ -37,6 +37,8 @@ PROGRAM Piclas MPIW8TimeSim = 0. MPIW8TimeBaS = 0. MPIW8CountBaS = 0_8 +MPIW8TimeMM = 0. +MPIW8CountMM = 0_8 #if defined(PARTICLES) MPIW8TimePart = 0. MPIW8CountPart = 0_8 diff --git a/src/piclas.h b/src/piclas.h index 11a50f0c7..234d1a08f 100644 --- a/src/piclas.h +++ b/src/piclas.h @@ -38,7 +38,7 @@ #define MPIW8SIZEPART 0 #endif ! Combination -#define MPIW8SIZE (1+MPIW8SIZEFIELD+MPIW8SIZEPART) +#define MPIW8SIZE (2+MPIW8SIZEFIELD+MPIW8SIZEPART) #endif ! Deactivate PURE subroutines/functions when using DEBUG From 90330c5bd6db06ef18024b2a1ee054e98f4b48ea Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Tue, 6 Dec 2022 00:45:06 +0100 Subject: [PATCH 32/36] Updated emission distribution reggie --- .../PartAnalyze-ref.csv | 2 ++ .../analyze.ini | 17 +++++------------ .../command_line.ini | 2 +- .../parameter.ini | 9 ++++++--- ...reggie-linear-rot-symmetry-species-init.h5 | Bin 7216 -> 7216 bytes 5 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/PartAnalyze-ref.csv diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/PartAnalyze-ref.csv b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/PartAnalyze-ref.csv new file mode 100644 index 000000000..f8d844f1e --- /dev/null +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/PartAnalyze-ref.csv @@ -0,0 +1,2 @@ +001-TIME,002-nPart-Spec-001,003-nPart-Spec-002,004-nPart-Spec-003,005-nPartIn-Spec-001,006-nPartIn-Spec-002,007-nPartIn-Spec-003,008-nPartOut-Spec-001,009-nPartOut-Spec-002,010-nPartOut-Spec-003,011-Ekin-001,012-Ekin-002,013-Ekin-003,014-EkinIn-001,015-EkinIn-002,016-EkinIn-003,017-EkinOut-001,018-EkinOut-002,019-EkinOut-003 +0.9999999999999999E-011,0.1364000000000000E+005,0.1365800000000000E+005,0.2729800000000000E+005,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.2935049538942454E-002,0.1650005540495363E-003,0.3100050092991994E-002,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000,0.0000000000000000E+000 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini index b69af198d..90f8e4e4d 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/analyze.ini @@ -1,12 +1,5 @@ -! ! hdf5 diff -! h5diff_file = TE28_8_PIC-EMField.h5 -! h5diff_reference_file = TE28_8_PIC-EMField_ref.h5 -! h5diff_data_set = DG_Solution\sDG_Solution ! data set name in h5diff_file and h5diff_reference_file -! h5diff_tolerance_value = 1.0e-10 -! h5diff_tolerance_type = relative -! -! ! PartAnalyze.csv diff -! compare_data_file_name = PartAnalyze.csv -! compare_data_file_reference = PartAnalyze-ref.csv -! compare_data_file_tolerance = 2e-2 -! compare_data_file_tolerance_type = relative +! PartAnalyze.csv diff +compare_data_file_name = PartAnalyze.csv +compare_data_file_reference = PartAnalyze-ref.csv +compare_data_file_tolerance = 2e-2 +compare_data_file_tolerance_type = relative diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini index 4b20f5225..458689ee6 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/command_line.ini @@ -1 +1 @@ -MPI=1,2 +MPI=1,2,5 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini index 582e83821..142c2c0ad 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/parameter.ini @@ -28,6 +28,9 @@ TrackingMethod = refmapping!,tracing,triatracking ! =============================================================================== ! ! CALCULATION ! =============================================================================== ! +!Part-DelayTime = 1.0 +PIC-DoDeposition = F + tend = 1.0E-11 Analyze_dt = 1.0E-11 CFLscale = 0.9 ! Scaling of theoretical CFL number @@ -52,7 +55,7 @@ Particles-MPIWeight = 0.01 ! =============================================================================== ! ! PARTICLES ! =============================================================================== ! -Part-maxParticleNumber = 15000 +Part-maxParticleNumber = 150000 Part-nSpecies = 2 Part-nBounds = 1 Part-Boundary1-SourceName = BC_absorbing @@ -75,7 +78,7 @@ Part-EmissionDistributionFileName = reggie-linear-rot-symmetry-species-init.h5 ! =============================================================================== ! Part-Species1-ChargeIC = -1.60217653E-19 Part-Species1-MassIC = 9.1093826E-31 -Part-Species1-MacroParticleFactor = 2E12 +Part-Species1-MacroParticleFactor = 2E11 Part-Species1-nInits = 1 @@ -87,7 +90,7 @@ Part-Species1-Init1-EmissionDistributionName = electron ! =============================================================================== ! Part-Species2-ChargeIC = 1.60217653E-19 Part-Species2-MassIC = 6.645565470903E-027 -Part-Species2-MacroParticleFactor = 2E12 +Part-Species2-MacroParticleFactor = 2E11 Part-Species2-nInits = 1 diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/reggie-linear-rot-symmetry-species-init.h5 index aabf4ffd4d6a9eafff317c461edd35eed407f676..54b6c650c44c2d5c07c304619c6a20d55219f048 100644 GIT binary patch delta 228 zcmYk#u?>Pi6vlCgjn|-eN5OGMq6N8F$dy#$25i9FKsRs%n{N*#vBwQ?1KdE|KyxM% zUip6c@~`tcuPcr-w|H^G-i7zO6vQ)sgPs#k!lDy~dHcU5!r4<04$`8PhD`^XNoNm9 zs6vY-G;BWD$Jy;3_7ilG#ZHZb*T@YEMQD}9HXa9$%2^f@n%H8g$3cpnC7N*27QteT Ny$<{orFQ>Puf9C3H>Usq delta 176 zcmdmBvB6?PoZw_V4*toxf{K&l1PvzVf!Usu#e^&-p98XWg#st@aq>@&74n?SCTuY| z56G4k4xGFWNc#$VPW}cIm)rUhe<&U&6R=}I# Date: Tue, 6 Dec 2022 00:58:06 +0100 Subject: [PATCH 33/36] Added piclas2vtk execution with DMD.h5 output file as input for conversion to .vtu --- .../NIG_maxwell_RK4/CoaxialCable_DMD/externals.ini | 14 +++++++------- .../post-VTK-conversion/parameter.ini | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/post-VTK-conversion/parameter.ini diff --git a/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/externals.ini b/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/externals.ini index 19510f050..e321b4f78 100644 --- a/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/externals.ini +++ b/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/externals.ini @@ -1,9 +1,9 @@ ! --- Externals Tool Reggie -MPI = 1 ! Single execution -externalbinary = ./bin/dmd ! Relative binary path in build directory -externaldirectory = post-dmd ! Directory name, where the files are located for the external tool reggie -externalruntime = post ! Run after piclas is completed (post: after, pre: before) -cmd_suffix = ../coaxial_State_000.00000*.h5 ! Suffix for the binary execution -!cmd_pre_execute = pwd\s>\stest.txt ! "\s" resembles a white space character in the command (simply using " " is not allowed) +MPI = 1 , 1 ! Single execution +externalbinary = ./bin/dmd , ./bin/piclas2vtk ! Relative binary path in build directory +externaldirectory = post-dmd , post-VTK-conversion ! Directory name, where the files are located for the external tool reggie +externalruntime = post , post ! Run after piclas is completed (post: after, pre: before) +cmd_suffix = ../coaxial_State_000.00000*.h5 , ../post-dmd/coaxial_DMD.h5 ! Suffix for the binary execution +cmd_pre_execute = ls , ln\s-sf\s../cylinderNgeo2_mesh.h5 ! "\s" resembles a white space character in the command (simply using " " is not allowed) -!nocrosscombination:MPI,externalbinary,externaldirectory,externalruntime,cmd_suffix,cmd_pre_execute +nocrosscombination:MPI,externalbinary,externaldirectory,externalruntime,cmd_suffix,cmd_pre_execute diff --git a/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/post-VTK-conversion/parameter.ini b/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/post-VTK-conversion/parameter.ini new file mode 100644 index 000000000..a5457751c --- /dev/null +++ b/regressioncheck/NIG_maxwell_RK4/CoaxialCable_DMD/post-VTK-conversion/parameter.ini @@ -0,0 +1,2 @@ +NVisu = 1 +!VisuParticles = T From 80ad64c5418e984c19d375e7e35b5b0c64bc4c76 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Thu, 8 Dec 2022 01:58:10 +0100 Subject: [PATCH 34/36] Added user documentation for the particle emission type "EmissionDistribution" that initializes a pre-defined distribution, e.g., from the output of a field-based or continuum-based solver. --- .../particle-initialization-and-emission.md | 67 ++++++++++++++++++- .../2D_variable_particle_init_n_T_v/readme.md | 2 +- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/docs/documentation/userguide/features-and-models/particle-initialization-and-emission.md b/docs/documentation/userguide/features-and-models/particle-initialization-and-emission.md index bd2defcf7..ed88fad71 100644 --- a/docs/documentation/userguide/features-and-models/particle-initialization-and-emission.md +++ b/docs/documentation/userguide/features-and-models/particle-initialization-and-emission.md @@ -74,7 +74,7 @@ Different `SpaceIC` are available and an overview is given in the table below. | photon_SEE_honeycomb | Secondary electron emission through photon impact (honeycomb distribution) | Section {ref}`sec:particle-photo-ionization` | | photon_rectangle | Ionization of a background gas through photon impact (rectangular distribution) | Section {ref}`sec:particle-photo-ionization` | | photon_SEE_rectangle | Secondary electron emission through photon impact (rectangular distribution) | Section {ref}`sec:particle-photo-ionization` | -| WIP | **WORK IN PROGRESS** | | +| EmissionDistribution | Initial only ($t=0$) field-based ($n, T, v$) particle distribution from .h5 | Section {ref}`sec:particle-emission-distri` | Common parameters required for most of the insertion routines are given below. The drift velocity is defined by the direction vector `VeloVecIC`, which is a unit vector, and a velocity magnitude [m/s]. The thermal velocity of particle is determined based @@ -190,6 +190,71 @@ actual computational domain corresponds only to a quarter of the cylinder: Part-Species1-Init1-FirstQuadrantOnly = T Part-Species1-Init2-FirstQuadrantOnly = T +(sec:particle-emission-distri)= +### Emission Distribution +To initialize a pre-defined distribution, e.g., from the output of a field-based or continuum-based solver, a particle distribution +can be created from a .h5 file that contains $n, T, v_{r}$ and $v_{z}$ (particle number density, temperature and velocity in 2D +cylindrical coordinates). +This data needs to be supplied in a specific format and a different array for each species that is to be initialized in such a way +is required. +This emission option is selected via + + ! Define the name of the data file + Part-EmissionDistributionFileName = reggie-linear-rot-symmetry-species-init.h5 + + ! OPTIONAL: Polynomial degree for particle emission in each element + Part-EmissionDistributionN = 1 + + ! For each species, the following information is required + Part-Species1-nInits = 1 + Part-Species1-Init1-SpaceIC = EmissionDistribution + Part-Species1-Init1-EmissionDistributionName = HeIon + +where `Part-EmissionDistributionFileName` defines the .h5 data file that contains the data, `Part-EmissionDistributionN` is an +optional parameter for tuning the quality of the distribution within each element. It defines the polynomial degree for the +particle emission in each element. +The default value is 2(N+1) with N being the polynomial degree of the solution. +The parameter `Part-Species1-Init1-SpaceIC` activates this specific emission type and `Part-Species1-Init1-EmissionDistributionName` +is the name of the container in the .h5 file that yields the data for each species. + +An example setup is given in the regression check directory under +[./regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v](https://github.com/piclas-framework/piclas/tree/master/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v). +The example uses 2D data defined in cylindrical coordinates for the velocity vector $v=v(r,z)$, which will be transformed to +Cartesian coordinates in piclas. + +The .h5 file `reggie-linear-rot-symmetry-species-init.h5` contains the following information: **Attributes** that define the index +of the coordinates and the properties + + T 4 + n 3 + r 1 + vr 5 + vz 6 + z 2 + +and two **array** container, one for each species labelled `HeIon` and `electron` for singly charged Helium ions and electrons. +These names must be used in the parameter input file. +Each of these containers must provide the data in a $m \times n$ array and must be equidistant in each coordinate direction. +The electron data begins with the following data + + 1.0 5.0 NaN NaN NaN NaN + 1.0 7.0 2.4E17 10000.0 1000000.0 1000000.0 + 1.0 9.0 2.4E17 10000.0 1000000.0 1000000.0 + 1.0 11.0 2.4E17 10000.0 1000000.0 1000000.0 + 1.0 13.0 2.4E17 10000.0 1000000.0 1000000.0 + ... + ... + +and is allowed to contain NaN values, because the original data might be projected onto a equidistant Cartesian grid from a +unstructured and non-rectangular mesh. +These NaN values will automatically be replaced with zeros during read-in of the data. +The original 2D data (equidistant mesh) must be unrolled into a 1D structure with one data point per row. +As can be seen from the dataset above, the first column containing the $r$-coordinates is the outer loop and the $z$-coordinates in +the second column represent the inner loop in this logic. +Note that the temperature (translational, vibrational and electronic) of ions and atoms/molecules will be initialized with $300$ K. +This will be changed in a future release. At the moment, only the electron temperature will be considered. + + ### Neutralization Boundaries (neutral outflow condition) There are different methods implemented to neutralize a charged particle flow, e.g., as encountered when simulation electric propulsion systems. Currently all methods require a specific geometry to function properly. For more details, see the regression diff --git a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md index 7424e101e..6d7b332f2 100644 --- a/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md +++ b/regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md @@ -1,4 +1,4 @@ # 2D Variable Emission Distribution - Read particle emission initialization info from reggie-linear-rot-symmetry-species-init.h5 - n, T, vx, vy, vz for different species - - Transformation from Cartesian coordinates to cylinder coordinates due to function v(r,z) + - Transformation to Cartesian coordinates from cylinder coordinates due to the velocity being defined by the function v=v(r,z) From f64f16cd03ab5a6d66b529a146f07f178ba2573d Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Thu, 8 Dec 2022 02:04:32 +0100 Subject: [PATCH 35/36] Updated reggie table --- REGGIE.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/REGGIE.md b/REGGIE.md index 609c79a09..50a4f6fdc 100644 --- a/REGGIE.md +++ b/REGGIE.md @@ -25,14 +25,15 @@ Overview of the test cases performed after a commit. Regression testing for PIC, solving the complete Maxwell equations with RK4: [Link to build](regressioncheck/CHE_PIC_maxwell_RK4/builds.ini). -| **No.** | **Case** | **CMAKE-CONFIG** | **Feature** | **Execution** | **Comparing** | **Readme** | -| :-----: | :------------------: | :--------------: | :--------------------------------------------: | :--------------------------: | :-----------------------------: | :------------------------------------------------------------------------: | -| 01 | 2D_variable_B | | external magnetic field from .h5 (equidistant) | nProcs=1,2,3,4,5,10,15,25,80 | PartAnalyze.csv, PIC-EMField.h5 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_B/readme.md) | -| 02 | 3D_variable_B | | external magnetic field from .h5 (equidistant) | nProcs=1,2,3,4,5,10,15,25,32 | PartAnalyze.csv, PIC-EMField.h5 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/3D_variable_B/readme.md) | -| 03 | gyrotron_variable_Bz | | variable Bz | nProcs=1,2 | Database.csv, relative | [Link](regressioncheck/CHE_PIC_maxwell_RK4/gyrotron_variable_Bz/readme.md) | -| 04 | IMD_coupling | | mapping from IMP to PICLas | nProcs=1 | PartPata in Box | [Link](regressioncheck/CHE_PIC_maxwell_RK4/IMD_coupling/readme.md) | -| 05 | initialIonization | | | nProcs=2 | PartPata | [Link](regressioncheck/CHE_PIC_maxwell_RK4/initialIonization/readme.md) | -| 06 | single_particle_PML | | PML | particle | nProcs=1,2,5,8,10 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/single_particle_PML/readme.md) | +| **No.** | **Case** | **Feature** | **Execution** | **Comparing** | **Readme** | +| :-----: | :------------------: | :--------------------------------------------: | :--------------------------: | :-----------------------------: | :-------------------------------------------------------------------------------------: | +| 01 | 2D_variable_B | external magnetic field from .h5 (equidistant) | nProcs=1,2,3,4,5,10,15,25,80 | PartAnalyze.csv, PIC-EMField.h5 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_B/readme.md) | +| 02 | 2D_variable_particle_init_n_T_v | particle emission from a distribution in 2D | nProcs=1,2,5 | PartAnalyze.csv | [Link](regressioncheck/CHE_PIC_maxwell_RK4/2D_variable_particle_init_n_T_v/readme.md) | +| 03 | 3D_variable_B | external magnetic field from .h5 (equidistant) | nProcs=1,2,3,4,5,10,15,25,32 | PartAnalyze.csv, PIC-EMField.h5 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/3D_variable_B/readme.md) | +| 04 | gyrotron_variable_Bz | variable Bz | nProcs=1,2 | Database.csv, relative | [Link](regressioncheck/CHE_PIC_maxwell_RK4/gyrotron_variable_Bz/readme.md) | +| 05 | IMD_coupling | mapping from IMP to PICLas | nProcs=1 | PartPata in Box | [Link](regressioncheck/CHE_PIC_maxwell_RK4/IMD_coupling/readme.md) | +| 06 | initialIonization | | nProcs=2 | PartPata | [Link](regressioncheck/CHE_PIC_maxwell_RK4/initialIonization/readme.md) | +| 06 | single_particle_PML | PML | particle | nProcs=1,2,5,8,10 | [Link](regressioncheck/CHE_PIC_maxwell_RK4/single_particle_PML/readme.md) | #### CHE_DSMC From fde699d431608e202d047639f19506a50dee7382 Mon Sep 17 00:00:00 2001 From: Stephen Copplestone Date: Thu, 8 Dec 2022 02:10:52 +0100 Subject: [PATCH 36/36] Added missing subroutine header with description --- src/particles/emission/particle_position_and_velocity.f90 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/particles/emission/particle_position_and_velocity.f90 b/src/particles/emission/particle_position_and_velocity.f90 index 26d2e621f..b0e284bcc 100644 --- a/src/particles/emission/particle_position_and_velocity.f90 +++ b/src/particles/emission/particle_position_and_velocity.f90 @@ -476,10 +476,14 @@ SUBROUTINE SetParticleVelocity(FractNbr,iInit,NbrOfParticle) END SUBROUTINE SetParticleVelocity -SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) !=================================================================================================================================== -! Set particle position for processor-local particles (only in processor elements) +!> Initialize particle position and velocity from a distribution given by .h5 file +!> the .h5 file contains n, T, vr and vz for each species. +!> Only the electron temperature is currently used as the temperature of all heavy species is initialized with 300K. +!> Each processor creates all species randomly in each element using the sub-volumes defined by the Gaussian quadrature and +!> guarantees that at least one particle is created for each sub volume (depending of course on the MPF). !=================================================================================================================================== +SUBROUTINE SetPartPosAndVeloEmissionDistribution(iSpec,iInit,NbrOfParticle) ! modules !USE MOD_Globals USE MOD_PreProc