From 7899cb4decfb8987cceb7785c789554bfc7b1c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Villemot?= Date: Thu, 15 Jan 2026 12:01:39 +0100 Subject: [PATCH 1/3] feat: script to run validation set --- validation/lj-mixture/calculated-energies.csv | 24 ++ validation/lj-mixture/correlation-plot.jpeg | Bin 0 -> 21850 bytes validation/lj-mixture/reference-data.csv | 24 ++ validation/lj-mixture/run-validation.py | 224 ++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 validation/lj-mixture/calculated-energies.csv create mode 100644 validation/lj-mixture/correlation-plot.jpeg create mode 100644 validation/lj-mixture/reference-data.csv create mode 100644 validation/lj-mixture/run-validation.py diff --git a/validation/lj-mixture/calculated-energies.csv b/validation/lj-mixture/calculated-energies.csv new file mode 100644 index 0000000..05385a6 --- /dev/null +++ b/validation/lj-mixture/calculated-energies.csv @@ -0,0 +1,24 @@ +,t,x,density,u,energy,energy_err,lr_correction,acceptance_rate +0,1.2183,0.5,0.8,-6.991912,-6.824332775509206,0.007332089000306406,-151.9222906615277,0.523858 +1,1.2183,0.5,0.7,-6.28399,-6.15696393793348,0.0115122047621387,-132.93200432883674,0.605872 +2,1.2183,0.5,0.65,-5.86756,-5.747027114561171,0.008533981399021708,-123.43686116249125,0.643768 +3,1.5096,0.25,0.8,-5.87326,-5.728584068606758,0.021466385837235483,-127.1877273361547,0.580572 +4,1.5096,0.25,0.7,-5.2830446,-5.1486481236643895,0.015199454304553882,-111.28926141913534,0.65148 +5,1.5096,0.25,0.6,-4.57915,-4.457067486522425,0.012901052999909882,-95.39079550211606,0.713526 +6,1.5096,0.25,0.5,-3.84601,-3.7550796383339944,0.016097072216878654,-79.4923295850967,0.767107 +7,1.5096,0.25,0.4,-3.145625,-3.031679704426388,0.01957993121178323,-63.59386366807736,0.812887 +8,1.5096,0.25,0.3,-2.446133,-2.29186093973726,0.019961432466160035,-47.69539775105803,0.853689 +9,1.5096,0.25,0.2,-1.71833,-1.5204237232517432,0.018705478102023994,-31.796931834038674,0.897772 +10,1.5096,0.25,0.1,-0.88341,-0.7731743940092469,0.012321114326961577,-15.898465917019347,0.94422 +11,1.5096,0.75,0.8,-7.528813,-7.387557821039766,0.019429067147871005,-178.9234450957788,0.515488 +12,1.5096,0.75,0.7,-6.89008,-6.705393398859641,0.024860213510585486,-156.55801445880638,0.598998 +13,1.5096,0.75,0.6,-6.0058145,-5.844619979911088,0.01211174105592481,-134.19258382183412,0.674251 +14,1.5096,0.75,0.55,-5.52616,-5.422084348147788,0.005698415488936215,-123.00986850334797,0.708598 +15,1.6438,0.5,0.8,-6.54401,-6.36678624267275,0.008473648040505592,-151.9222906615277,0.557943 +16,1.6438,0.5,0.7,-5.95657,-5.844425928860567,0.013831459037555685,-132.93200432883674,0.634995 +17,1.6438,0.5,0.6,-5.18836,-5.085670690270235,0.010455755569991681,-113.94171799614583,0.702152 +18,1.6438,0.5,0.5,-4.35859,-4.21187686179021,0.010561762660606716,-94.95143166345483,0.758437 +19,1.6438,0.5,0.4,-3.549019,-3.4182878823413763,0.011275107483718705,-75.96114533076386,0.807701 +20,1.6438,0.5,0.3,-2.768327,-2.575420052801317,0.010850764609473712,-56.97085899807291,0.853085 +21,1.6438,0.5,0.2,-1.936931,-1.7475874342217939,0.01920265179952064,-37.98057266538193,0.89591 +22,1.6438,0.5,0.1,-1.004111,-0.8560035870798322,0.012956204273870288,-18.99028633269097,0.942764 diff --git a/validation/lj-mixture/correlation-plot.jpeg b/validation/lj-mixture/correlation-plot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..abfe4c1b4a743e8271f65a8a21c377189aa7d415 GIT binary patch literal 21850 zcmeHv1yo#Fy6(XV5&{8&dxE<=30e@`AwYslfZ$Fc0fJkA-~@MqdvJG$!X-Ea2(GWv zJ$I%%(|zAech6nxt#_-|URA4V*EzNK`Stt1|J+UAEddXtB|s7Y3=9ll2z>%~vw$do zjEIPYh=7cQgmmv7G71_tIvOe}8a~!T3~XWoQW9bUA|f&>CTcPY21+6#8g5z!7FG@p z4pM4fK^`^%CUy?C?+1aockdn=DjFU-IvyK25joqx{kUreFp*)FV7=gAC;(VY7&uIr zyLNyS0ALWH|MvSI{@Viv77iW(5efMo3MzC$IK#hL(&p+T@U{F-_`Rn;}Mb**jf9i3g>J-wr2;}erp(=(9emDRN`>l>R}+lNQrj!#a{&Mz*% zuL}l%`*~S^U)c}q!i26179JiB9_jnKU|^k~0}c}&ft(c)>!~8rE1QQDY~IM&&mupT zw%ns+S31Daw;e&jrQ%qAeE5B7KdtOvTbR!uTG`(h_K$Tz05mul=*5G>1cZUJOPX{q zl>Z(7AMHW*=Vz=)NZ7zOeZWCyV$qHe_9&-JIKBlf=a=`~SPXAw_Ru!*yg%IQlrJ*B z16n!r?||W*V(?<3@GYwdF)_{{_}8CFUQ=q7+}y9*xVb3516HwNMn+z2{P5WiKl$Io z{9?cUcW?ezZvLOwDI6Jd$Oagx@9wq2U~+W4m|b- zvz8j~-ySJ5P7J(#C_@fdIf{Uqmu%hCCdmD;6-5w!Z*blL6V=0Gc_p_+pZ&dfn-F;A z{dGwkcwS}BMu7LCCXXN=6=Ztl_%8fw?*K$_5A(3_E~fPzkRDs-aFwwo^57;)_^Zqv z04BUPy`lmy#NFO^w=Uya@Yi=B4>flv?WS=JrU6ne`khz)}@LwS4LbavR( znXf(c$^q=OsS6w$7H>VuuXw9*TA_RXN zER`pyd2nvYHM)7<>?N*~koC;I`y!nvQOb)iRXp1{NIvYN4JQsJL8A+uGbb|I_0|tG zpE?nDrcb@#RjxFelOb2`O?40Q^j%)8fH-$>+{h?ajfZ78VBhDw7t}c|Awi>!Kgebi z#WP3)H}a32FaJl-+JK*r<(N*Ym2OuwwtpM|v4;-TXk=8*kEJPQcG^8kOEID9XmW$UQj-ObY z_>KA7YGL#8% zgKR@^>rc5)N*;FP%rT`Jpz3XxdGwiv&!5>{Q(j+9SPHjc_1WDNt>DL=DF7c<;m){j zd-+qrcYuz$X&pkCpH+{!UzVp)ifA23zJOp9d}4XbnUR}bYj$%3Uc#rdl26E)AG^Ib zbdGcjTJ&$)ePsEQoYQT%!`%T?U)%IfQLFBN5g8pE{nyxv;=peWBlEh(!9)f#MBlva zr&Eu2`+4LI)};c3pN~IyE+A{-V36wuN2+boX* zDz7Dzz#^TZ|5286;(;M~z>+Ck!nql?<1J#9Kh-^KC-rwh889Ms?*V!P^$BKW#Js zI$$S+b_Yc1rGcj@7ViLYM*E#J$adL8%s5eMd2_*gUOBut4D z8Aimhk$v_DrxYrqCQl)Ri7tpFv=MwPXGp%P8N>F@MNcZiL8UTgF=`rWGq6%XGg?gx zT$MS-0}B(eifYp$t^NJ|WkyTOwzuD?Udl7rRUoKQEgkR?82c9Y<@bS2+>A~cC0fP9 zRuJL_p0oL@sWGq zfRrGbG}ym-l${J1$c^kiPk5Uod=KmBh*X?-M_BEUpK*D#f(PL?Z^TQu-gkcXQu){# zjWKKLG$oIBoYQ!RJv^4#kT{^}s7RF)XFz#>yI)6=x=;S=W=J;&{~hpfkm;mmAU3%r zTsCAm>At`6jc|-3OB+rDEgEZ~4OweC8XySdj41Qgnw9Oopv~Q>-^ZT11Jo8p<+7VD zt1bzA2Eon3M{?It@AR_X`UbmlM4f+$^n%)x;12ktQ+*qxwV4Z~2hsfQ`1vpnKYO=f zB=)7Di^rEpH$IGaz_HSlT$8;A{f7gS>!=&J+ZNnA;F8uNN3TxkJmfRU2E$jO{%{mMlGpHp*^+Va(cUb+n{nQ@mp`-o09Xu122MQQ&o2 z3d}4yrGTLWj*O(QmaqD_L+!C`lzFwnGfUZix4oj(X98VhF$Oi!m7t|C*C`!wz(#A; z!lX+}cCW<0#H#T4e4o;6bY)&F#WWm2REiMJ42jImICT}(QdGTcg2TcZrKqPqpf^|{ z)>Q5B<2S@*?#&7*EIIoJ;*Kf`@LUm%jY$uBXk(>TRm?Ed$zG;*W~T=MbV&bUX`*ZV zvgW9^u4yar25R5oK-GpC>3L?CNm^bWLA`wwTKPMk6lKG!;&Jv`V7wRGZ{&Jd>ZS-1E@clx-1F7>&U|AxFO_mo5YK?nUmnhfSPet zkmd5#p6eG*jE9k5^5zjg1f1DiHJycDoEDd=Dn85iQ(yt`0JW)5!Ah{t9l%Z~U3@8d z2>x>Mz9N~VOROBXiUoPBfTVC^BHT_rH@(!d+VOQ%P#H8wk7!M}1GZ;3&BlKgLlL4o zzze*Vd~R{u;ywQ%BNmiyV2I`T@|X4!sK zb)A$^&v5GUgfw1+x$tB=Ysm!5y0sG!&d=#+YcybKH}+?1Vj4Y@ek4$Z5_PYq&49DK z$g~Qw7p46|V1&cAaCivLG72C2p!bc0>k0e=DT>?~XC+jed6KL=!TvZ4Cp-Hw=6KuQ z`ez_NIAazrFC1UuoFAUWt&{Emo(e?TPV+{@u;1#1|+c&W4P8TNlO+ zuii0sO`V5Vf7{ZoqxLU4jwjhSBl)HrcVjs>S9+?qA8tPOX>5<9o};qNo7|6&E`0nl z)wNt@J?e{p@S&k?uhK^D{vCj@35{*6KEEp=} zLB9d~?Qtyz9=-P%AxT%p7)hYOj)T z?u~y^9z`D;3Oeoql8CS{h9~C7scp3_T~8|^d=Jz{;|NCM#}iC-ylm`tykVd2upK7r2R4BfX3S z!jOr@UpasA`!vi+>wSgppC3K{3I5%17X^|~?_g%iyqhXB#txsGbE3|~=n~j?+sU!Y z(JntKj-5e_RSAhQeShnS#5wJLs?yYPBgJX!;N_lvO;cQNRk#IfWX&-WTx3u4n%#hE z{h?!|QGQ>x)Kr;HTls*DhtSHKM1OULcPfT%Q%EZodRUMh+_*D7-DDev%e|Va)T^iO z-^C>M23x;(ybm&n{)S~UjJm*@Dpp!I$;@$MyFb;DO?6bbXZ50Dj1Gg=JuHg08$QCB zI#PrrMqCn3dh(EC8%xQn&NqUPD10z84fgLUo|8*@E1Z4@*ff1eySEAToiu-HM8+$k z)+4CmQzZd3Fcuivhn$~dC^TCh>TcWK0r?dHu|m7xw{DXTgH7O)Il%yb5lq@yp&YUs zi0fO@cJNT6#byc#)NvXhn^|S8Tja@YQ3-8~L8{giCf!b<-tE4NytJFs9l&%4M8@Zw z8?Rg*a>`@%R;yd|s}J%k!_!lpK9;Y1pc!6(CWu)pa?qE90*meJr?^M?7N$TMB;i7AL59UBsLMa&cgYABd z!H>?mcJ)@Q!z*4qZbepKb*uQ~s#l;!M>MO?uP(Otj9s3@MWN6!d%1=8HLQ(pj;`SH zp7t|Y<43-#BQFn53Ec?>ZVIcBe5?B)GBkti>%2U>^wXw4#e;t|_N!1)S7(`l^x3^x zCJ#idCuv5De$nZ7h$=O8qL|Y{+|JG-q!}ZE5%z{f-pVCA+BH(x4q5C_J&YU3GG5J|dv&UPM=!|7$ zT@1ENYcC5y%4gpA0wubpaGpU+PY%DyugKKXyWQ~hjt(AZ*49-fC{wP%#Xoo(5T)vb z1;X!mG0^}jzNy!_?eu9Wvgc6dn+ssJU1y~gqZ4^ft}A6F|1=2L-ON9I6lu=qP;`uc zRICq*7Igds@9AHt0HYv$4Hmy$1+yxTW849xBjB3Feg*jB-^pixB`v=*2Pd-F0z8BI zK%=3DY7mA8K$$8Q?r;swTHDIfm~A{Q7TOk@esCFQ<>dyZ%WWB$L6=J+aNy!l@2GRv zVmE&@$keNlQc!jL0T@oc@J6T7p+Yph!{G7YVU2G0W+IE7 zPrjU8*g^%&des7D4WC45zPx4TgSr<4e#vDJnxmPucmaRjKHj6&lvGw8oE_D5;pyro zXbkx_@d~3k#p)~f-W^~bZMA!Iv!KhKy0VjSy#14nqWuZIOa3|Ngy}zLzXf?hW0;r0 zU})+zRx(d2y)N(@4hMJ&Hp0!wnbVX_rE`XGL0nq!R%)8i-8sXbPCZnLQ{YAUNVdihaCkWM~8npW@~`-HmMzkyxye^&sJ zhfn|mfI7&3cfhDC#w?9(#PS*hPS}#j`IK=adweBWvFNefTk>bo)L05v>w#XX$!klC z%Z21jE&Z#r66QYQGNz69mk5P2*7p~jgZ3OS9&~=v4sqdoZ4z=n<<-7NQyfJ_D1Wh; zX;V?4LwfXE)h`#WVbQ7+0-BWCo8r62pB(%0_?9zIFfn$n>%VSZ5{Cttt!au^3-nOh z9+9dEZeQDEDi+$Lr_;3NhkQ@473tz$l#YP4BT*dPMg%i?6>j~WlL_i-LwN*>4Q zB(sf0PUTIz7~bB*2!0?B6?+6C40TCv8V2*#YvF@%a4Yp4a4+ty@TcphvYV2<)jeU8 zt!iV(ud_${^IyXzc4EF<>TCpZS|iK^gOQ)rg-!$^OpwUPGe~s{dwenpNuG7Q(rCtLO+}B3J!xzMm&dJ}zg|wIU2u|kQ3w881$(6Oj7?)^% zxNn|w%4f>wF{UxQ?OOjFRt&bf+-*roTEq2IMvMOUKtWbBQQ#pCitFL-=kmU^zvlZrHF((E8 z@`#?V?dd2-eIOG9N1u#YCY}qqpK9W^NI^)HEC`Ftd_IUP&UaO58c!5$aao{8iJsA6|wE^WY61JjIcoZB1azs$dZ{ekN+qjFVu74|&N#oK$MU zv${@Qodwu_W<2=po#&h?G4^W2{?NnC(YnM+ZAM^`0t-LzwaJDZ!A6aN!g+lgx7l(79Z{~dTt7onOhmip{fFajJ8 zQIs>$VTwyLVLVOzDD21wa+Af3?Y1Vh&9E7}Zn<*~2ruBQkus z6f*w)FSI7MDg5JB$9qh;)iECf=K_tCeR!5ks=!$s#k)a4^_9C04*ll3)Uj@zqYeBh z3yWb??^EYyuS%h|;zo7w+@(QurBPs3aJLE~T}85btNmQKE@y0Uu}S)?{XA2jRJpbc z9xh(or)~K>!2!!Y0x)jLPmXbjnzsJw)?!o6MSLBzKgC#%#nlWH|4@zoIxllA)GhoL zoNB(19@MLB>tr11<5Tf0h$fHbzl()`?SK9S{QNhdbCnZWxiN_`>T&B#)>)DIWS>~U zHvn7|hz#J179r8JF4A&#K#as_Z>6lZW~7wGlP>-84!JP@DL#To&lc1+oUB1~1D@1o ze~!!0tNa)&7a%jPKVGp#ULzHgoF0Rng6Hr4FhXhwufuiV=d=IX<^MYw+224|WRv=; zN>jC!6`BMS%yz0b*^({%>Vk4GORkFO^Of!8;t1_ZJ#f46m~D8oz_Qooo2MxOo&kWuOb^{LC=eQ6L{%6t88!BSycQog%OdR;F ziNjX;O0QNy{#QBgFK}xb)g&}ymL>`Jv=lj%7(Df2ow(e*=fEkeyw#qR z4U<->atEypAvv!veZ%KPZ@-=;UVnou%l7G;%gkgAOj)zbyf}QE9ijw;JAj!VKt%g$ z&yGn>l1-ND8+ErhnIF~-P$adzOlrfJx*E83DPqKEb4*~m@D&_5ZWwUlX4<&KFrO)~ zQy5KMywwSr;1)FZSlpNs6Ayis?x)xcyhPEWDU|j3S77hI0KwA~q8j-!Wv^c9v#TY$ zAGjVudWla^kA#5|<-^8-%Of=>8b20V@Z=3qhg_jpyzQSv9 zo1~}6(C8Ohb>h1jIZi`J&);@^%cmCSko&^w$THnb&$OpCBuPEhS#o7g_wgaN>vM=^ zCHwx7p{CQCmmJaqkGJw$;Kcr>Ur58BAkLTp5cALDd7`+Hc3HB{93 z>bk`je_i!Qr-5{0NzHT~AQK+t)dpL2^>wf3p8Kjy9)HE$=H`w|_!1Yeq@l&TYiVg1 zh&b0hYAq2BoGH9v7a{Q#rzorQSHhR-COZ&k1aP3RQrEHGKKC~q!G8$%zgVEekyn~v zI1Xla@L&ld6B%R!9Rm(&W_n^T@_zzAW-8~8chF>ZCc@K*2VTmr7T~W+*=uBuJKO_d z&gSFH?ynt_ZY*St39vF$2NyW|7&VSdvUY_-EiT=e&>e7FH=zu&lNUcP$Cq7x4NwTPq%hWiaKqQJwO+2b{5X3%hP@iY!a8U!3jedYhP7=RmqF%uqzp3{c*&(7Dpe zWyB^jbx3ec)PKGMrbN<%=-FET73uyy=P!_OC@_o^y?IL#HS|0PU1nLe=mug4auKMq z1@R6oIvP{kY`X|d6{?4dXEJt%M7Avt$jReC+g%$A&+6*Mr_Ha18In0h6^ngspL&%&gnW?-w=-rmE=12EA8TmjltMj{CfE+0thI zPEDv8LeQ|7bcJf$qN;`76YX|GmYD{MXJqfJo((RN!CCQMcyD~#@Xx5c0z7wYgx-w2i5*_lJt)*gx}wA)ZgWd`uJh5^ zM2jG+B2IbG>)qR3?)M=#pRx&bN(nCK?de`6-cj?y#|FXEqFGe&jMIgS@L*p;W$=%J zW#taZwq4IEzkM}ov7!u=&=uXxXyobWnL$xfR5yMbMa5bXRhMbb*53tSC|L}hoYfs} z7sUo*ToPCKK`!-GiM=SzLkv%LZsp#)%H^!o;%?}on`QgfF>(?j+@R%Lf|+h!vvgQP z^~{1uiY3<rjooFzuq6#7W!PgoFM9+(`X#6`1< z8YKZU6J7wbP?1lVSrv;Iwx{o`=TqjTa*GrM9Nhuv3w=ldg=&2(x}oS9&r0AQak0|3 zzBME#ag-Rg@r_~)Ix%mp8WvzSvB0Syu!=1e^L~Ig@(y@u>mnR#HT)Cd61d?zrbsJn_a(hJlfI z=*tH@YawBhTE~2YvTzdN%9hfC6fM@%vD`AReU#*toA7TeBz~@H{QDK6LQByO0=0Mt z!OFRHTK#u2{z}}wGam9|mjvUrbw0f_`%K0^7eHYf)~}v79p09n_JNElM_=iD8e)4{ zy07TWLrs)=TWKbj%2gsh7pH{j7+X@t2d%c_UL0iw1T1l1h6LfQVG;pn5vP|9dA}~$ z^M}U@Lksp7D-|5F1XIt(49Y7*C4g^4X!wNn1S2_gflL~f=jEKT)dPay$2U&Ul4u#% zAL1_mT=C3N*87=ca{EI~sCMxOP~o4MX-X3u9_-px+Lr3_RgK;+q)O++s1%wplSs~~ zzZFy{AO(Y4am?-jJ zKx3rRx5!+}p|K&(_z^4TN*}As_3F`En2c9LBG_ml>J@)V5ddS9tiWbCs!8M26~Tw9 zwOp5;1ttzGN}W8$>MxPp@6QE|#0YdJ!?YMtG@LarqCGxvY`Baz&$A~$4Cs4+-6@^4 zVRO3&xH3W`dVCVH$-zJ~s}Zfr`T6-)Ey!%Zy>+SP6pam2ltNI;l0C-&l1`jz?Cs!b z->z2Z+hF2$ROW;aMreg4-Z5lnz#3+dZ%2aV-khuIX)kI^g!Y+W-#9 zD^&TK>Y9eI(dpvs9R|NyVE2fHg{|Fc32s2rZB_e2gPz0km9`Fbzi)3#Huq%q)JSey$?J;MEaUUmF~!M32OZqm z);`wy;ND=xSW_`+X)h|PzcCv^2!K7B+@;X;>LBij?oDsaAvH3GJR0C1g_^wWzw;Yt zU|oNYZ4b4TfuG4IId0S-oxNZ7Ec+>x4wGp)*Azwqt}!b<^3} z__zuyJJAlIai%Md;UHeo1;5u{$+>%*ZUP%-rOI`Vy4CTPr0G0zxxM0w03y4lRWDO+ zHHk_o#oOs=`T2ZLcS6@Df17WiVf5S_T03qzbyAK9`LrF**iX$n7l}9il~|Gz39*sH z3&rR3a!j@&YX5Q@RonFNv)LMQaI|-Nl2?#lADd=6KUan^}EJRf&^Q+=-T zoh@q-epLo#%R>2uC_+=DXGT!AtmQ4vceX5K^>(-EY_F*`yt3?be&FP(xm zx6>jkQq_kJGZwFh3hbx(Tm2}7g4XSmmnwNC*8eC>UY6css^Zo1Qy6g~xDaUhXP9Ma zHqP&Eq0vr!I5~x@JuTKFs16l6OU^cxtOo4|-1g>NZ&W4=w{btJ4$MD~RjsSn)vwh1 zu0>Dhel9{zCXM7AY(wA2T|fyUIUVVHi&NJ@lLQ{w@usm=3REoA;)<84%3sw?)60J1 zz=M=`pjlroeKMcGo|+AhI{M;jws^> z^;t%Lj0WOP2*BQjvuh7Pxu1lx(i272MK9~B!Hw950TP$K9UAFg^cq`}d^(@1#&-Ai z$dD-LontwXHUS*|pLj)o#>@T}fb`2(TOqc?lQ`csp9L8grs8a!J}eeOb)Fuf>(#J{ zrUDBtzQ^&kpFc=6;z%-Vj7ZwO;L2KN6zz&LP;FEhRW&%;i^*7|eX+sZ-Q|vPQ-E?Ro5lg+S87n4xtr%CY?YO-BOR4+%4& z?Pn+?+O@ncpbcKZ#=J|6fFcfb0zoc{v2-8&^%j#Js*PEyL#-Q{JXOv<1fz?~(5HF{ zT1`9F+soqEYL9=nwDHST{@>pJ0L=V>G6*zR$Dk~&ljVZ<8S5mW36=t(nSpO&U@DaB ziFgCv4guls9eGM#lyKa3$K5^v)8Aq_-vP_0S3-6-NsDGz)MwoLo%0P=GfAEfTlRmE zjsG=#n~~yNl;)BXNfC&sIkyC}Zwf2Da;?2OeJyNX zC_Bx}&oKx&+Et&uX07Ib!>;SCt7x&xD5YuP+CJqdv3Fcxk*J}DpcW<(>ww#Sv++86 z?qM7IOSGv1XaM@VwDBq0Rbfo?F=wHj?h#H#Huc)7YGx-YP$N~0qL*o=Z3EH6PHsa5 zq_m%-0GpHtRXV8ceEvR{R&kcRl|kQz#$K65sW5B>s8Q|1li1o~yjFi&upO7+qEar;0x>V!B8TAN&J~bSwk{%?qRvlRK)xHURanWqc>WoFqP`t+DolQ^ArODVf-_*nO^Nn^-mYS4V=`pg> zkS=`o=T`}68+Mq(YX=#`fr8G{7L4+p=a%B6^261LGS(NCHog(sR~es$FFWhdh1*=Y zqTSD`2<&msFtA!jDVAb%eXr$}y;FRu&S;Aq;+8_J>FQ0J9^Hy*kp?hwD11Y7OWblv z*tgOdIwn~htbzuT?~{^e3iZ>AzPk|V|Hy^<%UlXH1r$NRNz8K&5F0U+I?*wZFO7Oy zi@W`Wf8=40{-{9#1PxCy+ipp6Kj%Fp%87pcC~ z6HJxFF8h_i$&zx_b-1yiHrO;BtE7#uJA)$|_DJ_hwPq$xt^|n+omjT-kCKx?w!Y25 zoUmrVoDU-~{{YYYKIbFy0|h&Ym*Kb*TOrqI?@^(25Gb;axweFGR6u?u)I_~(c%O4~ zImjf1#u}k`%rT>O6~^Zn4sVE>GmFp4^;k?UJ-oyKTG;Xn&fZ2QAEroE`W&&s^Y(f0 ziGK4N;X%6f_~k&VMjh?;hefC9yrHaDiC{xLz3?aF6F2zh!>fefR%IsKN|$|K)NcM=dmHVUSGFb7kn7I?<^-LHcb5T9sx6kvuB@l zkSI-cxJ7RpqPjqRuOWhPOr`Pn1BAaE}*9Vk0gU{env`*pD=<5V)D9`0u@dBaJ>1$-9#P~A)3V=H`MD2B zQT%DzAB95xo!|X=*yNWX^}or0P&*mI)Z8=;e6qFwWra{fVv9;xu5BSne{DDL{d?6l zQ=J8EjoFGbmm+SW!gLCH}odhCwk*IveLj*7w=Fqph8BFu1kA(a$)jusEp~6)oU~>eI`Uu7d1}C zDKnI~HS8t|#lHlauA{Z;5^TG~FXHJu&p1xNk>Bs#Fx_ARg+%tCyjyrEBzYuDs(+Yz zgH$1W{jd+pwd0J;`@c`(_~|APKOV?Vm>|B)F3lluZD z85-gaH>Dp3K5s9~TAw~I2 zyTmY(*&>^5NJb} z;Kw^)DMjxVly*NXXyb<+{f|vqsjLsj-<-tM0lzl2v#zVIn!SmpTOEj}m`|-BN&FUe z-i4F(gGByxbC4f)b>x3=&ZJeM&8ncp9iU!$J3YL5J6NY}xj4g?%FfcowCj-(e)6G9 zkbS|6UyDBJhi%K))n&f}(oO^J03R3d#S;q!g;IJPFK#i>Uy&TM6>%vdr(l; zu(#%$u~fCm9#Z!8>Sxvtz_CJ|_lKR6{81?Zd;9aFBXK)aw6g)plJMakyF^}pPNd)2Y=ZOW^{g$IO7kR zS%%2gNSnRPi!&2KVvXzzf;E_&&;-ZP=?t2Bi*tlSjYKV0R@QX3>)2Zry>TzyOFv5| zJ?J!sOCs_2Vt_bjNPQk3Of|D%7(+B%h#mb<&E&+KSZyqUL0GR}Mc;Le!)|uqtSnzT zVZA=7cso>JR@U1eA(nd;EIBGz_|O6kcSvo(4dEC2tHB+6%V^P~)u%E-QN?&wkt!E6 zhvE1zm-+x3hO1x&ox1IeMciqFv17|Al(Fzj^4c^uD+Q-PGkwo#5xq?AS4)c8x6+i6 zPBgJk0!#M`;V?eJ*6eu-lCWokR?%JQ1(o0vyHk427*u_61{af}-V}7Mrb*X zyxpT7PcZpV@sTQ-3&ikD0+XK!5tU5IvjS%LA3=cfc(h_ve{qbB1;XHRK%IBibEgZ{ z@r}bYRCxmFkA~t7@GNNT-MmN#WCTOEi=#vDz@Nk+$@1OYh(O^RFYl=7W`QvFl&76^ zZxx(7xtWDBKFWC$VoJVZ5KlCNaN{S!IkF$6u)lyNMkQOR5A5-*kNZd~`b=CNPqdn& zQ$E*R`bI_Bi${rq!)Mvt4Pk@Xe*X&*#EHw>;j?<%Z58X_7NvbdFsK$0mT5y2(R7-6BaK$U5RD-gz z_^AQgCvE|7b~2u|p0K8_YF$&bz>d2;Ct{VL$cX+0DXPscS`R+j8@S z?BK^yuwx7a?xjL3uI$g7?RHIJF0F&@b+k@i?=fY5n@8=8*6zVb$jE!P4d)$sW~c42 zkw6-FY)x?9I(jRp+oE62mL0E8Eno41SBb><`4@@d7Ipkija4tf`@d-GEF|m$<5sQ} z8ReTsYUAEOHFK!3Ikky<%=-&)T7@?C!yPnVrec5>eI4lc+odqLF6e9bT6(fv$c zUmw9u*!f=~8-Lk*b<#uJO~@9XrbXf=S+q)Zn4RHKVG;h|7ZUYByG`D-`>jFWbf`5a zDhk#$5Uvv#*GnwT3?X%W8?Q~Ld)52fKg?yAxu4}Y?`YN6jtZ#0B=?Jxs~HOcjAY_s zxyZvQOVX}4;YMjn_zt;B3MD_D=ZH@Fg+vJl6qhirmrII6Fe68NS=Vr1JaFk*(k}!R z>zbWu<&GUEx)s#R-XC=C6?;A!YbG&C8LJA>puzuAI_bp^q3?Itv)WNRcs^SEF>9Oq z!FDVR)+9b-FE_-1+)&ckNRan&D~_AMqwta1o^e<(O+18CLP^7i z*fnI01QFV#xgGSa#*@q(SHaxQoXdY3RaQu5B88Z1eL(ahX`RrUwWNdQQ(o9i^b(AB zpYe3;t^|_{zv`ez)%o!R+dgRDAbRD`9^KqUM&d1Qo5Fmk0>N2N%+aC?PF$wH7&74; zZI9gRIa5Vg(cJw=_y3tAO)UGD;EyP-OlSe=-R&F>ej`*S~i*!@JzqZp}|hj+70 zuo)>$@dd(Em;*Y!Y?IF=su`!YrIH{g$pXF>HJe0PVT#tiCuW!m7D%^Y?J0BENsWMT z;T$U7MqQbkUir{tzm809Sj}fRGtB+?E^AmqMndUcf&@XUiz)%x&0GNUmbB(lSyJ3zOBCJk-gTC94iPzmB<;+GLm?eC1o z5Gj>I*DFOStRVTMlOITLl5lzOCJi`$Z1u+R77_ zR+f;NrN&5A-;rjaa;L*s3*?CBfCgmJU+d6_28JZ9BlB){+@`n#wB@VfZ^8-2a zm2!CEZb7B?_1ag0UP@bq}dC^vRP4UAg}|@awHYXuq*)u6kcD2f!Pq0 zHwXf`KZ$cy9q|8HxE=3.10.8", +# "numpy>=2.4.1", +# "pandas>=2.3.3", +# "seaborn>=0.13.2", +# ] +# /// + +# Comes from Monte Carlo Simulations of Binary Lennard–Jones Mixtures: A Test of the van der Waals One-Fluid Model, https://doi.org/10.1023/A:1022614200488 + +import itertools +import json +import math +import os +import subprocess + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns + +# Different from publication, because we start from rectangular lattice instead of fcc +# It shouldn't affect results, as we're not looking at crystallisation +N = 1000 +path_to_exe = "particlesmc" + +epsilon_1 = 1 +epsilon_12 = 1.1523 +epsilon_2 = 1.3702 +sigma_1 = 1 +sigma_12 = 1.0339 +sigma_2 = 1.0640 + + +def create_config(n1: int, n2: int, box_length: float, filepath: str) -> None: + # We do a square lattice + # Species are put randomly amongst the sites + + with open(filepath, "w") as f: + f.write(f"{N:d}\n") + f.write( + f'Lattice="{box_length:.4f} 0.0 0.0 0.0 {box_length:.4f} 0.0 0.0 0.0 {box_length:.4f}" Properties=:species:S:1:pos:R:3\n' + ) + + species_indices = [1] * n1 + [2] * n2 + np.random.shuffle(species_indices) + + number_of_particle_in_each_direction = round(N ** (1 / 3)) + if number_of_particle_in_each_direction**3 != N: + raise RuntimeError("N is not x^3") + dxdydz = box_length / number_of_particle_in_each_direction + counter = 0 + for i, j, k in itertools.product( + range(number_of_particle_in_each_direction), + range(number_of_particle_in_each_direction), + range(number_of_particle_in_each_direction), + ): + x = (i + 0.5) * dxdydz - box_length / 2 + y = (j + 0.5) * dxdydz - box_length / 2 + z = (k + 0.5) * dxdydz - box_length / 2 + f.write(f"{species_indices[counter]} {x} {y} {z}\n") + counter += 1 + + +def create_params(parameters: dict, path_to_params: str) -> None: + with open(path_to_params, "w") as f: + f.write(f""" + [system] + config = "{parameters["config"]}" + temperature = {parameters["temperature"]} + density = {parameters["density"]} + list_type = "LinkedList" + + [model] + [model."1-1"] + name = "LennardJones" + epsilon = {parameters["epsilon_1"]:.2f} + sigma = {parameters["sigma_1"]:.2f} + rcut = {parameters["rcut"]:.2f} + shift_potential = false + + [model."1-2"] + name = "LennardJones" + epsilon = {parameters["epsilon_12"]} + sigma = {parameters["sigma_12"]} + rcut = {parameters["rcut"]:.2f} + shift_potential = false + + [model."2-2"] + name = "LennardJones" + epsilon = {parameters["epsilon_2"]} + sigma = {parameters["sigma_2"]} + rcut = {parameters["rcut"]:.2f} + shift_potential = false + + [simulation] + type = "Metropolis" + steps = {int(parameters["steps"]):d} + seed = 42 + parallel = false + output_path = "./" + + [[simulation.move]] + action = "Displacement" + probability = 1.0 + policy = "SimpleGaussian" + parameters = {{sigma = 0.05}} + + [[simulation.output]] + algorithm = "StoreCallbacks" + callbacks = ["energy", "acceptance"] + scheduler_params = {{linear_interval = 100}} + + [[simulation.output]] + algorithm = "StoreLastFrames" + scheduler_params = {{linear_interval = 1000}} + fmt = "EXYZ" + + """) + + +def run_simulations(output_path: str) -> None: + df = pd.read_csv("reference-data.csv") + + path_to_config = "config.exyz" + path_to_params = "params.toml" + data = [] + for i, row in df.iterrows(): + workdir = f"./tmp/{i}" + os.makedirs(workdir, exist_ok=True) + + print(row["t"], row["x"], row["density"]) + + # density = N / box_length**3 + box_length = (N / row["density"]) ** (1 / 3) + + n2 = round(N * row["x"]) + n1 = N - n2 + create_config(n1, n2, box_length, f"{workdir}/{path_to_config}") + + # Generate input, and run + rc = 4 * sigma_1 + parameters = { + "config": path_to_config, + "temperature": row["t"], + "epsilon_1": epsilon_1, + "epsilon_12": epsilon_12, + "epsilon_2": epsilon_2, + "sigma_1": sigma_1, + "sigma_12": sigma_12, + "sigma_2": sigma_2, + "steps": 1e3, # 1e4 equilibration in paper + "rcut": rc, + "density": N / box_length**3, + } + create_params(parameters, f"{workdir}/{path_to_params}") + + subprocess.run( + [path_to_exe, path_to_params], cwd=workdir, stdout=subprocess.DEVNULL + ) + + # Post-process the energies + energies = pd.read_csv(f"{workdir}/energy.dat", sep="\\s+", names=["i", "e"])[ + "e" + ] + # Remove the first half as equilibration, just to be sure + energies = energies[int(len(energies) / 2) :] + + acceptance_rate = np.array( + pd.read_csv(f"{workdir}/acceptance.dat", sep="\\s+", names=["i", "a"])["a"] + )[-1] + + # Compute long-range corrections from the cutoff + # Formula from Gromacs https://manual.gromacs.org/current/reference-manual/functions/long-range-vdw.html + lr_correction = 0 + + c6_11 = 4 * epsilon_1 * sigma_1**6 + rho_11 = n1 / box_length**3 + lr_correction += -2 / 3 * math.pi * n1 * rho_11 * c6_11 / rc**3 + + c6_22 = 4 * epsilon_2 * sigma_2**6 + rho_22 = n2 / box_length**3 + lr_correction += -2 / 3 * math.pi * n2 * rho_22 * c6_22 / rc**3 + + c6_12 = 4 * epsilon_12 * sigma_12**6 + lr_correction += -2 / 3 * math.pi * (n1 * rho_22 + n2 * rho_11) * c6_12 / rc**3 + + data.append( + { + "t": row["t"], + "x": row["x"], + "density": row["density"], + "energy": np.mean(energies), + "energy_err": np.std(energies) / np.sqrt(len(energies)), + "lr_correction": lr_correction, + "acceptance_rate": json.loads(acceptance_rate)[0], + } + ) + + df.merge(pd.DataFrame(data)).to_csv(output_path) + + +def plot_results(path_to_energies: str) -> None: + df = pd.read_csv(path_to_energies) + + # u (from the paper) is actually total energy / epsilon_11 N + # epsilon_11 = 1, so it's the energy per particule + # Add long range corrections to the MC results, which is also in energy / particle + df["energy_lr"] = df["energy"] + df["lr_correction"] / N + + sns.scatterplot(data=df, x="u", y="energy_lr", hue="density", style="x") + plt.axline((-5, -5), slope=1) + plt.xlabel("Published energy") + plt.ylabel("Re-computed from ParticleMC") + plt.savefig("correlation-plot.jpeg") + plt.show() + + +if __name__ == "__main__": + path_to_energies = "calculated-energies.csv" + run_simulations(path_to_energies) + plot_results(path_to_energies) From f4c063076a0b9c68120df5736605e50014cee16e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Villemot?= Date: Thu, 15 Jan 2026 12:01:51 +0100 Subject: [PATCH 2/3] docs: README --- validation/lj-mixture/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 validation/lj-mixture/README.md diff --git a/validation/lj-mixture/README.md b/validation/lj-mixture/README.md new file mode 100644 index 0000000..02d7024 --- /dev/null +++ b/validation/lj-mixture/README.md @@ -0,0 +1,30 @@ +# Binary mixture of LJ particles + +This directory contains scripts to run a simple simulation of a binary mixture of Lennard-Jones particles, in 3D. + +The average energy is recorded, for different conditions (temperature, density, ratio between the two species), and compared to published results. + +Reproducing the published results validates the implementation of the MC scheme, the LJ potential, and interaction counting. + +## How to run + +The `particlemc` exectuable should be in the PATH env variable, otherwise a specific path can +be specified at the top of the run-validation.py script. + +The `run-validation.py` script is meant to be run with [uv](https://docs.astral.sh/uv/), with the following command: +```bash +uv run --script run-validation.py +``` +which automatically install all dependencies. + +The script will run simulations at all desired parameters, save the results to csv, and make a correlation plot with published results. + +## Results + +ParticleMC reproduces published results very well: +![correlation-plot](correlation-plot.jpeg) + +For some setups, the energies from ParticleMC are a bit higher than published ones. This actually happens at low density, because the simulation times are too short and we don't reach proper convergence (timeseries of energies not shown). + +## Reference data +Comes from Monte Carlo Simulations of Binary Lennard–Jones Mixtures: A Test of the van der Waals One-Fluid Model, https://doi.org/10.1023/A:1022614200488 From 2c000dda69c2e5c40f1187d3bb7c76d90e36994d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Villemot?= Date: Thu, 15 Jan 2026 12:03:59 +0100 Subject: [PATCH 3/3] docs: format --- validation/lj-mixture/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validation/lj-mixture/README.md b/validation/lj-mixture/README.md index 02d7024..82dea55 100644 --- a/validation/lj-mixture/README.md +++ b/validation/lj-mixture/README.md @@ -22,8 +22,12 @@ The script will run simulations at all desired parameters, save the results to c ## Results ParticleMC reproduces published results very well: + + ![correlation-plot](correlation-plot.jpeg) +On this plot, `x` is the ratio between the two types of particles, and the energy is per particle. + For some setups, the energies from ParticleMC are a bit higher than published ones. This actually happens at low density, because the simulation times are too short and we don't reach proper convergence (timeseries of energies not shown). ## Reference data