From c57a045bd6db248f1e65ee7ae486d7fae3d344de Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Thu, 8 Aug 2024 14:35:45 +0200 Subject: [PATCH 01/22] feat(paper): Add the feedback provided by peer review --- paper/figures/coreutils.png | Bin 30723 -> 40028 bytes paper/paper.bib | 2 +- paper/paper.tex | 82 ++++++++++++++++++------------------ 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/paper/figures/coreutils.png b/paper/figures/coreutils.png index 9f77f3837ed7a3748794438cefdb516d236fe75b..55b7c89e872ba2a1ac1df68e4c557c7072728812 100644 GIT binary patch literal 40028 zcmd3OcRbf^-?w&}k}?w6ns&0w%8bxbGRsO;C&W@7L?T&a?Q99zL`@5n@{$E8gYggp0ZNPmF$C$+$gp-PVI8RsF45 zqr*(AebwFvo}Rg@cOS?+z{;v-*7{y()v8r}+hp4KEeB&5mzS3_P3yn>)Gs}ld95i! z_^1~bD{GBWj=Z<0r$Pq9(QBneUOVv;x$ExUyEivKlv=g-%Vx0~zaHhtJUaKOxVZQy zi>GJl!T5;(e!l(x?~nce@gJuKT+F`CXW1qmA!u6AmUmmVWo3Sd=f&Aq<;zP8UOqmC zEm;;$bG@Nk=y*T**5=c1S-q~t0bQ6rRv9TMsZ0Ygg$=7SnG))|~ANl$0a^9`Q z#mO29M$sFdorNCt&rh@2-pArwa&ySZ%J#gnnx8VgTK%NVIL7(QgROf4e+x7CRYnN; z-1;+kI`5X<{M10BxM z{-M2~;BHzPFJ9-%!@XjjK0eBthv+X{yLL#5X$U{2s zgRi%~AOEGU!Senu$@VzJ|`wy$HC#4uIrM}nHO5m^a~#x zx{$%H>O40;Z`1K{IbJ9hK;j}tQ^t!1G+ z%vBLWh3)MzrKJkC9@82s;r#1dU0tV#TTWiPb}ewpb?Fane@#qDO^rXk)vkM=-8?)t zbar;`kDhUCk#HEJu(!95jf|?OQgH{);=$R4h3=uD$lv*%o*O6ns+6Nd?Mk1B2#^Jo z^V!WPaf{~O=dlJ`NlP)e0Jf7FFVFM6w;w&#R~c^Fl)=$k{@C!>*Jov%7EGZB&%M@4 z{a#+~jnkcU>&YT>T&?G4y?sZIhS&{#t9`8_X46-xm~!^j`8QX$*4EbcZR2b8Wf1aq zbE6<%wbiw&i1Pi-VWp5m7p$zTo*LIgi#yFe5-_fgcWCRk5H|mI=!nkyqS64ivH-RX zSIUE*8J0X;obC3%l*!}b8 z&)Hvb{w6J1hxPUK6(2UeHK!eJ$xhNpP!cq2*eE6S(YQH=T3NXwiBk?gOD!SkIKh5@ z)2@QzVvb^4Nj0&1pO53ku`Ddc)lU+K8&l44Vc|c0`qXfQBjEXS?r$$I$e>We`LB4J z-Y!_^oE`7JG4eB9>G6Tu7iUt8T|RnwDts}p7@@!^ALhMMPILC<`OnzM{byg&<>%)& zyt+v1Hq-7J^YrOHd4Hy=vLLQ-5nE0yT2W!)8Xg{=)oa%5*Ltr0Vj(8o-(M%lcx*eqShbL-8o7~@Qh#xF zTqTTmm9eog=cy;9Khh1$qQrz_T;}%=eNR=hUhz>-2)XqBhS#oxXQ}AuN-M(!(%-&S zowVb^(iIWJlWqH29!E8fN}zHn}5;s^HM zYAK`n3lBH#I>2l4^(p(plc*?bJG*sH(LAR{S|j-kzoa=Y+>~6N?fyP!=V%lBd5D|k zgw1fX&=-H^8dQVH&v)YjFDBK zsiFkkX8Vm>-`mN`%O}2=U&onNO!) z&SPKTH?CIs{#s{MX{0a@&T#_1Qe})3Gc$9{zpJAfvtviV4Si!{td;wKHJSoxN+9B57Afx2v9d1~&@=onMPgks6P*+3baZr@@@@;GeDU)F z=EZ5MXtVSggr=_uti%Zr|KOhhDn zTI|@dH1qFAw6m^-4=%6Su#J6gnO^w%Pl4j|Pmiyf9&NA5b)4ir_nL9@?n8R$qXTV6 z4v%^m=S64cGo$+{;)JM)`inaTVs$^dFdnmV!(g5GRm(;WCdO9s<8>KQdFbwbYEnzVs9`V65snW|qdr*`*s|k+3A&?gd7F#c8KqJhB=giBS-o)> zZIkGza@48h&`eZ0fByU<4rS7W2p}kbd{8Ay^f7~wnV!D>_@(}(QP&k^Y=8=z*|xo+ zvI+_cvHg1;245Ub9#-SY%F5Ehqze}?*2s0R{+6m6GcsH`=i)XyBU`X=0?kA*LXwS@ zbs+Y1ocy(xtgTW~Qe@tL7|pNv`b@^OEmwr0Y+%7?24D;XT3Rz+bMRAykoj|b zy1?n=;Z*f!t39^uRmyg-xOR=a%83&v2HL7Wf4=kb!kffd7lqLw$DepdZr%JvWsz)v z)45<8QmE;ApI76&O*OELGP}&Oyt!IsfO%|G7IDud$F+R=(Vud z;|yEYzrLJjcEBY(dic_%ODNy9KsqJ$_4S#~Xd;XKQY)YF1&bxAH{FxGyic%ms3GuJ zgtE{e}>jrwhc{WaIi~@+6~I$%}OJLhLi`m4juB{D|V9?K+fo-Q1B6*2z0GC zE=#x2rX-rPEPSG(_M)efk#284Lo*|_?ELsLhH9`;ar~4?=zdMkh@%$e6TKBV_M=Qq z8CTYHwQtA%VgPX$Pkt<2V8QF}5xyQaI0Bq6u2^qO8W@_|_+*U~SMp};=Y}J?`6|E! z$*1GiZ)XzM>-cm>D_Mh_tvA=2_|3k*jv8EU0Q_2Bn$e}ejt2g^YC81oRl|!jK22|o zckbBn`OnaIdeIx)yAEhQJ#lY+V)y*aXiZX#OF1fD_j%O)`|HredojE)2cDoCq+4}L zZ)29Mv~PC~9kl!1{*l=&@AgbY$V1ihwSB1{m-!FVM)K%N0(Ht@JYr=D9KBKcWT8@?9Jh30!lF>(y?02*_JDH)T~sxPwZEgmx2#pJX$;11}uOVxtEtGfkuuh zyIK_?2c+~|BVm)Iq@v9~~=QA~#M0dV|8)Xtkl=E2vDE6VlW%3w5V z8XB^)vUPG;-k?^d-MhauBx|k;6L;jdXwGE0m~{=u+y}omiM@*qnN+cGRl+Wv#KctX zcXTTMe0wzSWVEVhUeP&$U`NfnhXI86jRF-o~Gdg}fuuB{E|=+Ki~S+xDx z+DghB1Vr%F#x>(!yFO{1>ve2d)l(TBv~KfmtD$d)2OE+LSC(g_)^BBS|M20q_xE&k z^W40=RmU90_Pu`n`daJz$2=bw>oO1PH+&1#bty~JFZ}V|?%>uvN8?>rmT&y}dI#Jo zY2Jxosw?^`vsE0dtP?A5ueU~guph;TEE3EPKW5E}mkK^~p)PY6RE<%@#vQdWiCLEK ztIn|tz>%7fvGTjFYgObtm&eDCQrI`g#0c8YpFfj2s*zgxnK_L8SX>zWNEQZ6rzhO| zetAlFS64yCm5Me`j(9oQp8JQ-sS=p4pK>m>4<+DrJ$F^c)hh3}xb8hdRb3Xb-;2co zH%fr*YCyuMEwbOdiE|k5!l757#4iSXcXwg)@hsge2EYldWxTvNcPZC_K+2J}ybAQt zxj)}^K?M?WWGWv`y$>tNvF(3n+rKSN-meRwihNdZn^RAYeV!VqH*L;L&XFM=F@KdF~ca7!Ome7l0ZBh92|aWS_{+;88D$|>wod3pPielePgVKw^hc7 zG(~p?>`>Nnl|h|XD*q)j`rp2N0~ZSc+lmmQarC`RJDGgpO`q*y%Y!%)sUecA)c8*1 zYi&^^zwq~;vPYzc|NZBG{y3mSR!%NlY%Nw!?%%(4tVDy`e>wLUN|SUS&?Q?Bc2-s% zud~1^_{UKNqr>yz!>f~hRfKk&*VdlE@zhAYEHMa32^yT1p3Y|<#>yJF?LV)HIeo>- z)^-g!!WfT!;3sb!#trgUmT&(a9!@^{iUAEV$z^FC*m~9G&6@>I9)`vtLs~EXiDtEI z%gsbtp?TW&Rnjld^)qv-MXR8*(n-09;~is<-&qZTh0nN}5xYE7;EchOb-i`I>$8ui z!i#@Dg<{-x$yqnR?~c*Y8oZwfune|ub;nTZ$HepL23~^!?j9aew#=?8OTzejjHw`$ zLedNe^b^DXe3fk>AtA@a#3BRP!B5eNWAK7j_)wxZejP{ABx@y8-&?=c0E;7jYl^#Z z@_JLox`PJ~_Eksu1O@FByZPH;-8nYaK)!#)mcVTc%Jq4R+oIpKZI!`~pUQ97my9Yi4Q1cprOOHKE zTU76#m6K(^fJV!4?AQ-c*H5vS)K#t%;yL70&xD)Bjbk z;;$bR;PC*4q?*=dmi+bM4b;ew=f8n{(M$u&JL8``oUhnsFVu0SIxlC zFy_|F$B%by+qP{HVi*dlbC>*n)`@SY$)J#BmuStg^}wJ>w;#O>YOo#St`NVkx*)ai zTL7T*&i(uM>EnXGpUJW5trP66Y;I-%$#Yw^W)?`iEO`G;DycfP9=kJ`Xh0~&BfPRq zN%2GwEcH2N+qdPz&0$t{c6X3k+h1Q!i4Q ziZ`NPXsCGNz#3Rs_~9+q-@6kQMu!iH-;I~PzX>|UCL*-}6HmP;*sU0ZjvXnsHo)kg zVx90U4>?@%Ovb}uc8rDUqqIW70T#74*g^o$=>r8p!VNgyJ0+^YV6b?sy7^8t-0E&X z1W*~6NOfV-mWJ}g3=Fxuz8|OA;doRD8YVDS9LB;Js;~|cgO>l>v^2emo-(J!@siYi z{Ek764h~;a&hcn=6@K~hfJtBVe0)5Fs`}nVvyW>DgElt%Qe5i!Vs8jmeDg*k{ zjLN7XGu{P^1l0DLzHs3}fW+;aSVU#??kbvRc;|Tee}33_3=?Xsj4OtqLIy#TPf!e? zC7cf|Dz*H$MDV|PA~#{chyUpxiubVKV9`WX!y0Wuxfpa7+^4~bgUG-hArB#l(d^qx z(=R6f_iq(rW)Ug{ZKkNC#N*@gypLJqi}301uP%mytWb>ghU(V6H9z-P#AK~Gt~@~& zR$LA$VY}1hR(#2wkb(4Zx^q{S7s{B#pnQz9f2@gD47zL`jF~Z!`_JcdyjyExR2wTd zHQLU+XV0G9ht9hZXkdZ;D8v_<_GTqhZR+WO08x|uDK~FM2W7Z1^vw@io-MQnt)1jA zCa(U4WwL8Yr2x|=+4PoU(xe;LFeRRfQi4=hxiQCKrWB|GY&MExev@&&RY3b+MZx4X8#-mFzN;-vstVM_&!ja-z zLj((1cA0n13rC&jr#cI_OR<}Od+Gk*0sqb4=dW2n~osn5Ysi9l$DAw-6|MS;UWkgn;aCkcLfvq_F^wJ;QHejm}fzkDnwZaS_Z~ zf*u3*+&J|P7>0=MjL#BMNLk`IJi!+5+4iZR&xadG_w^4ze7c z9n-V4jCnqczat9k^z`(TW7c;e0ct*1e@4?Sa(nuauw~oYPY`&)bg9sIZ`{ZnprfUw z{r&s5O3NFgvb$&-c#k*6HAD+Q_cZ+C+X)Ovb{nb~BpOQmXkd}U!n6hB-o5FWDlPqA zuwMB4O;~L-%Li!Ep**^MbqUIehMQ=QsNg`T)N7+f`n-B&@uGz0;MqgP`Pe%Js7TMx zr0j;aW2((J6yv&#?z=6qL^bm0l_Jj_KOy@R-#mEsWd}fjFCAZjU~CaU3%JKPFijnf zi`K$!$Ebh0x8-9DrFtOCBbVNNLXrGx|LFQcrcjPQ11c({ab@(OoLhem2$_G2$EHFo z8T(g;!O^BadW{YRV+eVHQS7E~!Trr|Oln!7+3gImq^$G8%y0gL5mrWyl$MOq!Im|HV(i;Ig3VXF``sQ2tqPB$nfglsf- zavMrp4|Eo4eh_F*x>@4^!iZvGm_cHD$2tosuKh^611dbxcuqImg|n!*xD($*L1818 zT68=%1KtWxV^Jw4HDMwUN_tTPJvDd%*Tnz=8?OI6hDn*8nc0J0UD(t_4;dC{N)}E6 z_xUuv7bOn2Z%e%$1qbH?MDnKPsfLIGV}lODLHE*3yBc2~#3;eqZb*9p7<2Ga0t`M7 zfM#y4j3%$zLR6WNpE*rw`u74^C%)8A(UZx2@KWBbT^O~4-(LCLySD~nUtvkfNgOd6 zvcA~mx+FDbbgv5^T_iw+@hJohzia_C`~17c@e^w2qy$6etOVg<~yW zYQObH#{kTr-skfE3$_Q8eQ~ZoMkPiv3S6=_+fw(aMRO6VK867uFpm&sis9zBYdXNQ z_26_+KmmDZ-{!c10)ilnkm_HxaXbBZ@667#g5|GzYCqZrAu|R9EMhuU_hU3rH<3Q_ zm!>bGxgN9XIPP83glSGEV#5x|u8)-<92lx9c9iZP1&$p6fhe5gCCr)`Mv6EpaFUL; zwY8awa&lnS>kvoJBdlFgwc&!Nz5_bAt_*qH7#G!~w%W zaWIpB4j_)i=9toz;syEK|D#+(aTFY)L3Rn zrZFZ$J8$2<4J8}u!Ztt`0|*0&jYiPU+-7SxCn!B$t%pB>AN&A1As;qgJNtT6-;lkX z9f#}kA_a)a8Y?(5Zb@H+oab*u2wPTfV0NN7?nTXE()eQ63c8`&>;Nyc&}ZnHzDyDk zI1cr2Fl04n>uf6P=i4E007p&zZrX`XOMzisj*ec55_b;`J?H&B7X+5Lb~kPaVxx#J zmDvAB@$~7_FtK=>2E-wde$nHN{}Eamxld8U2uGKA*No|<=HNkB{(9iP-ygJbS%yLd zO~=5456)V{EhtC>Ul9wShGL|XxFv`wFJyn7)zUXs&S$k1lnU8;9s>gdhp~=Tz)30^ zu4{N3sU0U0f0UOCk4)PACkt?(Hj7xHrsh|!$f4w#-dVFjyiS5n?$rzpA`m9rp+kpE znltx9l-|eBA4rr#{lfLcNCqk+W03--t*RAQR9!uibN$=S*ZbkV>}z_rxVVS`t`L~a zUHD+D^3*#p+AXj_p-j~0I@-b)ejNX?;h|&mq|Nf8<3xXrrIP1yCqI8onVmE=!Dbpp zz(yz^V$qL$7^UOYqrk{hzFDqbkkvC?TvQaFv+P|u^gFp*ar<7;sRP}QzW=PxD4}n4 zr`&1M@H`-=@DXjpM^{%{kA18)zdqmF;Iy(d17GJ3e2fW*8e9>hM_5fYKiss)pY7W0 z8!nfVl`UuDPYbYnWj5| z&LN+~FVJLioxBc5#&7kyO&IPqsMy7Zo8(wS`os`er>v~ZAbec~;EY>4lN-_!FiC%c zUz_TYBe0qQKcIi(l^)^a)DwRg4z3sI5oSOa`r*EP``pmq>d`bY@Ip-3FPfEz4?FIM zn0z}Kz^hU#_TELje^8xbNc67Db0u0e zU8pBF_1h@nOmmsS%vz#8k`n{3Q?m%%^J9FQ$V{~v= z+3Rm(#szafa1UUkOmBN%lQ`_82rebe1@rRK;m{i9TQ^A@?`auBM`)A)F5L4oQOTZooep zNNb>Z62Au+K-^)>4d|EaR!nucfCuzCY;+m0q61FBFDzPw!D3I48lBk9Yq1Or;M?8U zecoLs@6Yzy31jl2CsW{+K$!htIpM+M<|(s%%5o}M9iim&~%OAC=kpJ z9G2jqQWGr!LCzs#={tNU0QzURHLD^ zj7&@f&7IkT*KoA1qFpZn?-8{PgFej6kIWOWER8o;RW)${<{khz6Z7K8yMEOt zZAXJjGz>J~Fs{r_%X9e&Afmpxxld{;5Ark$^+Q|}@89rB=2!0=muf&XDNZ^i5a}SF zvoVf$Awq3>mCpfNNDTtj+j-wob7-)4p|=ZQABl4BOD~{O;o@CdFEP~41*4-Aqpa*< za~Pi?^nAgmvR>3Rduy;}^vA6Bq3BcvU&!z?E#+~fCih0T|CNciV$lHP_hVpU&57cT zUMYvh6WW2ZKn@<+=@0E~ZIZ>cn@j`LBfG{KcCoUi?j)`?B=Z7@9RrOiwD6j`Nm>b1 zm+SWQ@4juyJ+H1{0%Ji3zNa#SwTM90Vu!i<^PTm*xRd_iJ)yJ*j2J<#U{_H9vBK0H zPSyn7tCai8(fLwvIx&$;z^klnYz%M&2FkS zfT2qZGq$s1`ZhhKC%_OfW!;h`izl^nY&byJ5CXA=?Ezi*1q8d?oBt>tZ!VxmW6nVO zC1d~uoO;*N&N79wsh6ujR!gDyaVP~pH7F*1jo7qGSWL{*`aCs|Il%oBh-cL;{iHnj z1}|Fu_eBHFjX-^xot;esNdj&S$EIK$@d43X?d|DVTf`&dJoW4JLuRRmV1j^x6vWiV zsze5I9654?Sen?1aDi((0)!*}Ig#Z64=&4d#_PAx9fuP{XaVvbUO9!-j)#K}oHA`V82TdrM_}0JB zEf7^vf^3wC;xUbo+`V_N1%m_`_jpOvZgFet(iIPGNU607*#8}l$=KjR2w&ln&Z6Lu z{m5-3nyzMDjlN90OK1jR@RJEV*J?2;55^%Se3lMT6<|20bphUaqe()SHj)yn`_;!3gP{bcHNt6Sm9=kR5d|(KH%GKj3pMU)L0pI>kt%=GsBM>W? zUoC(b8JCc+bUSxpGyZ+?8#Cyc9lgDBR#v?5jg9K!72!aB|EcelOKcL-0idf{VMFRy z5UnUS5i|gI0}HUec{33_6QH`gr^h`mjtx!K7&s0}7Kdok+qXj4xrXPb@8K9|zP=

Yw^m6ea>mgrFBrEKz-7y~?2}5Y0lFoE`RY>z>jbKu@cWKV%d^5bRS~nHOeq z2j1w-8v%5x;yV7hIv4bBR!+_@Q$OnJsF5?nUjZs~K`M3O_|C~1cskcggLFwKT@W2l z;1rBcOswwe-<}QQAMZKdzOoz&#Q=&j(gj! zY;0oT{v`IC#3zk*d>{7a%^TBVdf+x_Fh!^()A~fe#AryrYk8i~fJtnIA_85@1816} z$r5$&S+64{HNOijqo*{WTkeAsXU#-~VOb!@yZ7%C9be6yTk;to=2Kg4IK-3F5N_by zKQW8^^~(gJZXx8yjoY{Px7xQS0A_)wT$$Bdif?_HKeVbws< zQipP%#MD1DRDl`f_3)ufr{vP&;w+TdcW_4qvUPx8!7@6~Vv*R3#CYoJ>^uPtOjo-F zJa`fv(;o#zW*W530>~rL29Xfr)u9Qq%lNV^|A{(kq5WdqyVM8pxE~{?6A6J>fDg>r zvv%8h{DL1XIyg0)Jb#`JlWk_UPN9nIU{e>;h+0wWco zUcmnX#Oz0I45xtNL)^QEt>bDU`N#V2cnf_1PL(Ie_!?~`+m46;iXcN506{@g^W~j8 zcOd;npfU}Ro5BFW-027GIRw+P*r<6jYwPyyCGG9Zy1KgimL2INosIzzCZWTq4O=1^ zTE;2sW)x$-Ls1vd69=spv3efp=5+wJK`F8E$u75wfS-4?l$l z0|+xAX6RE8MXEh}Hh+RrK#VScpm>~Nl3%QmTsTz4 z=26FbxS}_qf1$^*8um}XuiJ4X9ExZILa(-+kg-);FeMZL!0K+5u}&}of&K#LTbLe>1C)aibU?@TvUl!t*cAXY zVex$>ARJ!4zH2*BSD%}j!ZA;}Mn)cDeO9kY%!5`MiNStnX9#3P2-<&8qRqF8IXum{g}=))K4@X5re|nd0vs3}v6FZ7K`ngLv|1SrvZ*mV9b%ju3a8h<9+VY01KpdPTQD`GUKrns@7u z#_v=}umBUHwOK%bpjk&@wrgHH$Xe5niokpFLyH5Psfw1k9T+8faN-5t$(D#MUjFX2 z%uwA6@cJ`txBZE6PU4%JqC zo-(Qo<0H%+d&}8OOHW^hnhxjHUkz|=@b&2lNP5&XG(|Yizd!+@pYiSeh&%vflq(T8 z1+M+z-Nq!2P_-Tah9I;Fgttgf;&+<0!l#&NSax=D`qljQAmPivA5#cd;E3_!_u8Ci zbfESZ;O)vn4)1|30prGimyXB<Hc&WmydCMD%p0i83xi zV2GtQE?j^h8Y@&ao^B3B#AXD%u7}i{Az)~EW^W*Hilm*cv<-2e(ML0orvisj0unZD z&zHcYzty>%dMT#>zA+~1%?z(}0Hpf3liQIMt$1hMO>|Mmi5?PuYq|-%1Z=ez8Un`Y zJG@lv={-2ahM02@4Kl8`iV`6Y2abSyQng6@BZ0}WX9ztIM?pWr%v)To#ofIW0y_Do zAlF7yziLUmPI3IF8mBA;x@|ER0Ar=Kx56L^N#lDU!Lkiw)WOkFA836fjs2ddw|5tg zkD{3i@k9{d$8nQ|Go(^{DladOz#%wm^aoD2AtwtZ%F+!>`bfm~Dv5Jqis~xH5c2?9 zYHB=Bfblp=0kgI@&Rej83M}-U-O$;LrIT`U1Ug|F`@VX0m}EbI+0^nLU_$Z3ZNQ8t zt}h72RSfOpi%H}DF=B`LdLj8EsS7Mxg*zSVi&pA3ZQQsIdNCC7rJU#?V>>W65~*y; z=oQG0f*g)>xawPwL+1%b+*ico)?aG3gH$Qr6)v}pPsezsf~v}-EpLsn*yk+E?J2%DFe z7oUzXIE@GlQmU9V2b=j5fRN+kxrA`(r+eK2b}`}#tTq~~t)-hH?n zgI!ac6L0|$i$D}2vdCUY-H~`ZI6-m8t)&X|hMSyQQ2^e`A8EA;TJ5?!nIim6J@CtdSI=h1HMW_;J z1BhQi>vuz086{+PKXq!y6KmFQd8!s8NpAljbk2*bPLM1sAF;@g3lo)lqe~C|sS9MS zv8j(bcWU>-0#Azsc2yuIC)MZ!_Xj`2eHLl9>UsYvv?^>Y)w z%9;!Coj8)?*jQ`0Kuw|cV-^#201)_l(%8f$;^VVRB0FNpK>q}GEZEKPG|%<0&O~qiE`?4-4@N<5@nCp>ad!+3&Yx9{qIHZ24WV(|4a5B@ znUV`C0itaD$(ikZc|HfvmFfxKYK z^mt4h9#7ykA3s0UKh6_loifDgNA5e&A`}&Y1Fr;Umw-2Z9S(7EMunD{{hxqjau5wc z?I#)nsg~Ydx0&wfwe#NT`3fy1I=I;aok%@R@3Y`uW=2MpSK4oYH7ee-thT5*l$OdThnE3!2WV!8H{fAxH1pNPfze{f6NPfS1GH>K2_ZL zE5^Y_nI)L6mBD5yFM}Q8Fxi04pyeE>(t{F<;ltr<9!R#g3H%PDRyL_gBCPR=r4wH8z7fQh4iHisVn&UXh ziPa;-^chgCn#Ff`IxyeSF}I`P3k8K$lQrf(3{$noMy`O-%zn)lCqmrYQjU`XH&kqf znX(ZgkVNXs`1WbpwZxGow?84j%7CyP12X|;RPr>k!j~ZlSA<-4;i3jH(Gb!g0yETA zJzzy*jRCR2&MgCLL6C71$%7(MiErB7-7N$3@tA6dV`1>Ya}TjTHb}!m38cprDMEd~ z#St57`Pu0ee{gg6&RtAPOH26Psu4-nc#VU#2aaI0^|x4lOu$S?w4jv3*kA)4AlWS3 z4!J`v0^m@0^z~hxFC-xt+#*PaedkTHzW|EM9Q5xwsMV%0eL;Bzc5&XH-6aIwI+%OM z7;YzpQ`1r|EzHfOBfLlQ%_uK#=vmjVUk7Yl17iaNF9tOdAG^lyzcw0lD^oBfjCDG&Y>zmES*)UQIrx{7PF zn4cR!q3d59D@%X#2D`beV0%J|mNqo|_18h43?%<>pM>1RXf%wAjeQQd8Eb*FKtvg@ zERI8zd9EuiiE1&`2uPGhONfy{uj?|$ffNq`X+WMFEucwuB+zxNty|0sn*I9KdaW`z4WI|A)Rw)X!4PaB6Vu9DxHvfI;fb6h;Q;+`>`=Iu_6f9f;BV5F8kOurzF?jKq%OZ)E z!L~jfudw6ElP5&NffSfn%X}c1o0X^h+qa{&Hu;c}d(h_v5BIlV9NT(u2VPb3&Sm}I z!u_{jg}Cf0^Mnv=pnV_%PD5hk1}-kHU6H}UmrYE#A$}3(5SMNFZcUk}dO66Tbwt7j z<|@k!MG6fHJrq{B+T@Za8otGRQ!fB1hoD?f!tG|8d~(SMU4-n_Mtl@$!qEWaNZuuo zz|-ei?93@V;+cuhgt(Ms(nJ>W%RB@L?SQe?e@v z;YzzQCK!zFR@;~w2xP{_{WpBoDFEkGDE&)Ly0WuN0eX`Q1t1wW1{)O1w(oEpW}5n<0})V1UDd*TYvBp^^*yv-0D^&@SH)m#Mre$OV zz79NuiygYxHynzGoeiKlwLz*nc)un)%^Zd017^$R@ci8O$;rtt%&RIYl!c};AxHDy zR@r!(9iG7(piOd1;rMY1WZv`v5Q(J*t9tj&ojdJ9xnY%Qm@(Qe zw73(k9Gg}taI?BojTXUiKvZDMnxeW5Oo{fvgg?OVoy6*N{NWG9X4aiymE{X&a>;G_ z1C;t@vcKle_s)~II%*MxZX7-d-^uLtrHw3-AX^6^Y>@msS`sA`b#eh1`F&6Hhq6s3 z(!=aDJET3g8(q8ha+8F(gv6PagcMoNE*1`s`v_QEiI}s-INH)_e5)fsax4>)D7waPMvYmR@uUDgp$faZg>Hk$th|K*~I)rL)-!o4tX_`m5Hy@Ln;Owl!@%KvZ>PbC4 zMxfX+rhO$qW{L_56w6YJ3foVB40=J&l$Vz`dwqE$i}(69Yt|r2gVfnogsw2UJka#V zi4dhF0YpAN1M4;9z&@XHSs_fsNJC)fLO&aG>>)^u_?!%(rjHr>5dbS^!uA!=kgR>n;Qh ze1JG;ofC*<0f+%FL|4B>}wi&X+ceSHa zxR(J^1=ca68+HLBQG|tsksK(P7<{<`nAQML29}ooiHV63DfsRIx*)aE>grT*^$bWx z603-iDj)KbP?2OHE0K?}{-2L=DCKn^@V|9u!8$Z7pnY-pwZ!#?H1sqf;eK>96YSOU zsq_2y@24O}7v?lSEN!ScJlV{iGa+YY$?q~rI&E}IPTr4JccyBQq%Z)5a5<%7OoGLo z`vke-K~5A{HNujt*c6-*qFfT22Pz;oMDBdnvr-@jsjGXXX%vAG&)HM5GQ$@r(%E zjSB2_D!yGt<4tfO{xl_SH;Xq-f=2QPwR@?(^)l zXVb{_Wh7CK>*|tN5=1P8e}{_GfmjNRYD(-Qxog+4Qs_T5;*Z+ZNIJE5%hs)pmy)TZ zJp%{fz>*X&Nju}_5wu(k@m~W2R~(%XmPO!s4L}J{<`mnxgPZP9(PtiTr;_G?JkZdf zElQMGD5P;$TX$={?6KvL>-_jeXXrMZ7(8?F}a=qC?u4@#~wq6 zMNRwTvM4ZhH;mEGctJbZTlP&5zm*b5m=={rFJcqVkU~4SZ|ED=L!BO11rbz*cVmsG z`w&4Kaylt9j8SUOjQ~6Mf`Wq9qSdf$62j;tT09hTyajG1cw%ozMqXBSEd~6?7YRQf zD{%n)Aw!(<=GwErqugDc@CuxkbN2Lj5qGM&SV&Lg10#J*h69o(kTbUeM(E*WzqsgL z?~K9)SJ6>z++_DiT^8T-S)$ef5#-xIM#}})THy0-*>iM@L*DNplqSjWqN%H&OeU|- z9S`U*{^w6G05Exm5J>y;^P8KeFoJOvPzc0YMH9%7kWbd)w;#DgDX+AV zQVvBxV}@nw$BcmrzP~;n|3T8@6uXaHI{&n=mV_1oH7;abqjy~#-vE2f5IYa_#9qSj zK1STJ04Fs}%>D=rO!E9Bvcm8|uN>oa9%u%XjDjXfoJR2AH_o&}79fI^V>tlf1cq8IFG!Os*iZzUz%9gpbu9TtLzgPy*!GW@u=L z1COJkvvKq0ZuEzy=ot`g0ig2AswzHV;eH&qHRP7b3qx{~5IqJHjEG^< zPpSNE78oW#F=DiL2R~x+Jbm?Q>BQU3*s5Yx8ykM07&ajxq3?$Eb#-Jmp#+13cX;#t zUApJ3aJ}g8>;PilL*;jOx<+yjk}kx0!;PHdZzY`XI^o0bN!d#Y;dQp2fu#VglH{+@0@=7PKmp8f6)^8b4js0&?8Yf0BX$Ct(MT?| zUCw}qhK$mW99u4Q3?hx<;`&Dl+6^SfrYDhn(g}Z5TNT zZV+l@FI{2;kE3H?AgO4;19JHvW)Tcmu6hxu=H%7~^auWm5^y~!bV3TW7F&>NP-WBF z*mY<+5b(ZYS12GOU3h=PG}_oc-pAj+9|q_m9z@_Mnh%Z*y24Ccxv$W)Dl01~o?pu0 zCm0O747Kd6-6_bgAvG(i0N~v?end2ZVvu24&q+=UJRgYTm-8ErkTXh)kw%_pa$!VS zNr@F26Ove`XYmqVhIS6G-loC&@G zKu+Lr&ef||bFwl9fBpK3r%VuK7Z4Sq$|u}=d8@0e?1N%XmbACADIYtcj<@~+i!iZ7 z2hS!$pT%vYo&m=ZKw@leIuiRtMxLBB#89VznM@Q}aIMPiQj2aOA-f^MvO&;5o%Ws& zO-$s(JBNjb;}pum)28D$+PGmG<32py2+zRkxo1xHR%!L#y?f#Rf%TPV))W@rgDqi; zv^G4-)CYsIE~SI*euS>MtEa#qp{AxLpbdS4`>_(qRRLIIrEMPeo0*yQnW{&Ghtq== z78MnZ0eq`uzsOAi$BIiy@xf)v=$hJwh9VF##KwXG1Eoz&p1%+%LL#Q9NR|LnJZV7@ zCmxjkM6y;Lgf9CRukhL^hx)wR_P`aP`)M3wn%gt+v<4#60rqina)K5=w@MzjB2YU$sl-49+w#;`0w%#-j;(-gufDR;K`X+fmCl-++MA zStT4?T*l2Ifq{YMNu_vS5$mqCNCyI-MFQ5_03zUQ7vr*5T3T8MObim+z>f9PQIY3D z;3&xZ(yhvkR&ZTeb|x1aAqz~*`jTg6L4`aGQ}IwtKfH8D$c5kmr#izib+95g`I`v4#4g;scN%!v}KG6jl^L**e%B;)ehhDv*LB;{@!=+ z<9kHwn0|p7<(l1i{ajb5e3{wwPOeIs~`$MH`?Qn z$3U)r_x1Ien3*Aj;f}j-V7wR_ME50+{~*}}VgR7A(1)Z(A^c$h#I)I{}nu_|^{vd5 zz_AVv4rWYUIHIq7S*p5X<}6u^b^n&}8C(&-^AygkI{6-CpWI#sbw<@`T3EtV!9I|% zzzYjdPeR|&-7{bYAR+GU;jsZ|8%JuJtE=nOpFgXfpG##TmJs+4=A}9mTg)FAWmQ>U zFubw%0mDB1;N4ee7ptriAcm30T0lmRfOb{~0E_t_z;cN68Z`S@c#~k3^%$`B@9j(g z#THQqB+-VuR00rU8Z|zRYTwpB8(a_q8s7gtHsJN^5i$GJp6PVh<1an;p&#e2*?Q%= z;R1m#;^Z@^-(R11FvI_0JpM&sMa6O=GZ zZS$Pv7eCHy)wU5k!e!}kn0dl_z8~AqO*3&hf-1IWVr*<5pj}Jvh+JnDw05NJqZ$VV zSSDIjvCie_MnAGGnL!$!qPYUO@A^em0bYkKADfw}Nz-|zu4iiMg{UmJ_PU$SESt1% z*(lRn+92=`B2C#-WtI%} zNBR{DH&cyhvq~RbLXq4L|9fJza6TWiP_1%UoaG~n4al@sy(;l*V`Bn-6VB1a#xoPI zM`uwM5kQRTxbcRJgESu5f;J15Nrlt~YHV_}jFQFXOmN@7uReD|ddF#2lAv$p@TA5A zlgJYd6pwGfxBo_s9bRS zFjGmQc?I9ybg`rGLC@7)Sx&wzITwb5SaP5@2+UFLSMo&?hTJz8;g_XEWRBY|^pP!($=c@R+hYXiv~b{-no*;OtzZNys_O&wg&>>9D^-r`&lU zZtx$?b<6%!|-uOKZI!6Jui zr*B{|aXLB@Sntn4CA1}vo<92@tTHw}>k~8-m6W`HPIK@F5X|fC`SPmkrMz2@8yXt6 zv@!$vS2iq-9}yH1B4!xGcfg5%?#2f9TH~PiL>BO~3-jpX>2_)gN=oJ95&Z1gW5CDs zFuch1LtF&ZL~F7OW#2?O_fZARH5?!i&*c1b>4OxixfoD&0&npeF{ACDKuk;#SMy2nP2#|0k6+r zc8wyT4+#G2*RQ8w=inFzdqT8cmgroU^p}Ik8cE)L`CbaFP7Vid?EM0{k}WKpy?SWb zfwp*@HoBCVNW%C9@@PANp?c(4=r41-Q!zi~uC!2WpTR1!im?kz&?ts3i!({NR3Z>S z8VWQxL&Pc|Ya|!ls0W~0hl{q2{Xl{wWe8wihgTx95)xDn%Znmljf)+wY~=AQAU1fm zogA`e$hkO1x4SRktAQ-M7_@bEcE%l@l@ov5{%VwZkd@UC#ukA%hf9_0fIeVmjC=Pc z<6<^>G6lqI$fwE=LcLkZ^);vICS#DYj_z*awn9fC*Y|M^ptSu8_&xik1K02b9yYX2 zOfy(xxJ}ssUrqe>v@cHD<$R|yKm|n=6)oo{j~*SDmcDzy1n{XeZ3zQZi1hnXsI?pwEKNjgO5z#fs)EuQ>_ES&O&u#We$HXcaRhF6}HisObw#p`k1} zmP(^c1cjj$aqZhj0rwFFZu?|OLu=iJ4Lg~bqV*%6J!8R<(R6MD=*6neeSYStk!*y^ zN=}f!$W2=ca-jj40)AXy1to~-p2PDEpW?hgzfgSp3T`d4mZm7-=do^Dsh6W3J)*J; zeYP9yhCK1=uSt`A(f`k%Kls$2z%G*1Vlt370*N7cW1Nm>VCS&ENGc1;ScBGEbgJ0c zeSKNvlpsEZCr%g&+3o++*O`ZNoww~@dugLGGg=g_ zM4MJiNffP;NQ-tYQz%8dV1f`)I!8%X1M`m6E3GXSQCq8faP0)t)+(G5JFNm!# z5wBn^F!l01{58037kLWY;_$?Rybc{ZQunt96UE4Q^hWQVC2(?-uGRkd-3=#8=wLYzsH4tZUo8;C*hksfV<${#!SN=6#h%y~ z92y#`I9cSDgn3wqGZZiiJaQoCZ&P!xq2Bx!L9YOsEdfBg&;u=^4belw6 z@n=G9u!r<1UxCvX-y%bSRu^WgOqnu8l&i2J2jP%7eR6JOhLalO67$lOfT^MeMh{2d zA40{*!)dY>j}V!s=dP53>Y_Ff4KmG-<;)M1$ikP=1ZdBR)6P3=9ASmU%%MO2XoQfr z6-6ZMp#7D$C8$H^HAx>D845!zgA_DyOI@xaYZt8%1=Ai6k9Nqx7a>}y8veIUeVbl& z`}+0Mv*M1PyUD2*MGe9ndzeqvf|*+H01m7g(d$h6n<-G7G|yFEdep?5((QC~bo6^i z64Ma{KHPvc3!h|Xt7~euBF2e;1}=ugk$Lob6wo?$Bs;~ak)HMWm-12Q;9nD(X;xYw zG-7P-I?#cFI0n-Q0nNl9?v;cE?&pkW5UyDgJ5b?S0(H=Sr2)Y5u{W}F+HrnPe7g}N zMsTqv06JP-e)INiM(uMXY2d!9Tw-=pMBSy|)gn*qFth`4a4=2um-lBbLt*M#2$+j7O_+W_c6u?FSr zTLNfwjSl>^9uZL5V<7-3T3Jf638yVC@?md0`q>U){RKrcg83~3Q8EaQ!V|1xFIG-6 z2t+edQQUpFoK|OOa>8qtc##au)6Ed4;xrt;;So0kl$rIWXsog z`+#e}J7+kVcfa-Q*<6*wGNX;!N4)NmlJp_US78fnrjIA;&#uBy21LDGDR8^DzoLT?Bj3=s8%77=-EQT$r5F(E**@imbih z@qjHe^56T++`GaqacX5n^F36RGVu$rBmRc;v3mg-8_P}rng4&W85mFwF!nRt&wVR< zCvn9Yo6rO=<$Kph(S1B??o}lK^9gO9;*g1VA%l8`80vb3@Sl0 zOSHy8DN?J)U|ro;^u@PG6r{xB>Le#YsDhaK*oolDJSSrih_jaUc{9==0biBik+~@> zwc0{U2w_3)$-tMMwU5>};H%F56I3wR>rr46>T3S_WpQz+U!j+to}PTTA_ib?CGZ}i`*hHb|I#0Kqo{2`QX}CmsVzcqpK1X zH{YPEon4KSA!jd5UJUF3Fk(3Q2mi;;T!=6>ui`ZmJ6R02> z9U#FOC%(OVs;hvvPUJsdza|eyfI!v2RL~OQ<2hSRp2S>~pc4wTj1g;w$uA{qTPFQ z;(q3S`}cdf)7PhK`5rfL_NL>(IOtTHYO>V1iO0}r%p#^ELzPj*vVJpLUIu!P7X2sj z)*c|KY(V&5vutg#G0Ma^A%SsBQO5{~0LK9gItZgfkkT^#@Pd=%ei{qDPHwH`fT2xQx2Tf@5M~$bN7howsE+nLcu>0LD#y2N%);H3Os$QL8wwknTsW`lguO@;4b>;1O z&|;%-b`lc(GVF1rI3FN);ozb<5CgKZ0TD(sBP>mG#yT?INcARuz|1|$bohqShs_96 zjP~t+TxP(99UTOqORJm?vtc%MYSx$UpQkEPy&(r21>ZrvwEXwqmn9u{uqNNiV6E7Q z5g@Qu?xv%oBa_U`5sBf%5}Dj&I2z=+g1fP%AlaNz=82)+oJY~!(LdIkh0;FUxueJ@ zC1#^1Po6A`88&q2Z(xCV|248}(HAB4B7PJ#>pqSRr`HtqFX&bX^{Y5+LC=Upc>x}G zj8w{M0tHGSItMTrt487#z@Y|cUQ0W^18h_hDE*Ciavj%q@}T^|A>VK`o|`-(GipfGPMPtI$~#YVjx;@@0Q}RmdGm*i z-EKVU?Jyi63w4UPWk6mBbjZQo>tcgj-j3Wcx8fWMr}97$Ksv{HR$nV=gi)LyNQQFP zuF~-EwnF%HIC3RFc7}3~{R0CLXZ^FvQ_5N)+lCGun(3n3+K0=EgaPf9d*USJ)Caub zPjC#BMQyr|o||9nx}mgDz1WvGO@auc{pfI*yWR>=6nLi>7)n5`$ho%GkQ=o1O=8c4 zhMLki(K+70kc8FLgG&J=&QqpDq5p65sT*xPDT)QA&$fEpPka1$Xl@B1 zu5_-aa&WKjuLB)u9T%XJrk-_cqZ<6)d-S=_)m{`7=M>Gv#Du07>f;7eXq@4kq@|qS z{cZ$S8tCIouY7uak|~As2ZnR0u!Jaw-+;3s8a+qI!=QdyrC>APn@4~~Wn^T?2ne_m z>B48lo?oXM0O8!4L&>bG-4g-&Ao0oM-Zo;3#WG|rf4vQjqp6yPa1DfwakOkin{7Ou zO0v4~$M-qp$N)~mRuHk8&zqNTP=5bVP>`Kpp8m$NBd0^rN&Vih)Bdh`|BNn576Cbz zN5onGSjVrK*QQMyp{}D&rw4v`r{z15!XuSyBqCmvz|Ae%ddYwh;F$)Q zj5v6mw%@pY{_cLuAy0eg=p0&j)6EOu8{3;R@4X*uMD8de4K75B4T$yX_3PWRFK40q z3G$z3|LA$$sQy(8GIBwR_H>qs7=8U^Ek{4BJC8`HtZ?5`Fd=Y|o-@LYeyko$D&TB* zqDN3k&o$~~M@{+34;_?Vm_U+R5tXoL zd8yc&48l{7e}tao*s#KAl(;Z3a2IT)B_d=(^u2X;d(GMprzpKmc_<`1vcnMClV*+u z;06q9Y;ZF&oivGj+?vX_AmS?w9v{<9f<7?Drm&wJ!?euIdeHm0sCeGA+6_6K`OHk~kG zFGVg*;a`-f^|p^x1Y(}pbNoSzZcYq#fS`QD)!@McCD1|&wA+0BD7?<8h43~)UHvO4 zdD9)t<`6t){#-=py}NGvHYuhVwrH^cl7b}PQdjqqtKmR&Lv-=>s>grp(#6N$UnnHq z$$nWfY%h6<`t7bG+|bXNZ%JNuakgqWpFQ%8ABlG`M9A`6OtR}urbYjHhL6{1WsEU^* z0L8k$!#>^@o?=_grwJ&6?~&Pb-%U$d-Fx_O>o1M-DYU<227{r(f;5Ka&KX4w#64=g zxm&NIKfB{ap?Pz`S(>Gb+&ZT%YD^uAoK2`1dTwYztN1fTxz6a!`uX0`cF-|D`TPPB zhOGN(ckgQFE*-IP!v?_-s0sQE8}{XlD>rEs^a&WfOg`dZE9T#-!+&fibAd>-Oe#)=zgG!aE3z=>| z1|qJV2tRXX7kCna>wA9=WO@bB2xVXD}{Er)s!cw0ss`{boPMK=HOiU5~0w3%Al@ z^-XF{&ag2j{l1R@jS~wWa3^<9En4Zk!>{Hg=@qmYRexyGSNM*b?nq2F8E$E5DU}EI zXT(-F>P^`(lrxYhJ5Pk&NS7(W#>34Md!Cn+?1f9Gh=d-FaVQ)uB$#HW^wnejk`Ca@ zsEsTHc<|tXL9@0Ww%7s7e+S(~`RcneO29*sKOY#jUm}ZNwDtjSnAlHa|DO0Hz1X+!)1x9^-CO&rJgObzNc2Sh3!5KT z>V2YSlDYdTD#lmz5{4f3MIwqPZBK0>Y zP^b$T2`tdKS>0C6(p}o7FLIGkORXx4!l3i$^L*A0{MDg(FM{k#Qm6QNG3+civ5`5N z1`^~8W@#*bu9}E)k%mE*P6!v3XtZ1D>75AP{qt8_ll0Kq6g@FlFW4m!v$v+^KIWvw zag`Rhk&F%VG#B#j5ldt<*C@%7+@q^KwlxUAe~4wusU=Ku$S@+XVT4Bj2Z(Yl;r;!4 z#6V|QH6oJ1)*qc{7;~;s(4ZCCMQJZiyV!OBbc#)X&fx!#J3iT7FPgs@%7hXC_lz^+ z+X4rQzozuI8%Gr~ndpe*ghCD9B0hg_G@Af(ZENa`#;sq!o;bpEuGCmmzxH?i#l&6f zyw;l!2b4_5621PWP-3`Aq9QY}2Kfc*b}5g_8g$QKRdU(I27{VJR5_1QpBo3@R^``b`wIHgpgM!bX znVr*Nb^x?Q{2-k4z-Nz;AV{YzrcnTL%pi_J)FrI_?ChK7c6D1jWEKfP?mqrH)q);IHko?$<1^L+eV7* z*r9{v^V|*^ePvZ3!CDTuI62rBSof(AITtD}_1wH4TvN<^m+%aP$-SIkP!L3U6sebI zQmfdmow!BB-tbI+QoU&-c%OaCp|P{=nRE6g)Mu3MPxVI!Ky(FLn3f;v{_Wy_81OrO z>JK$FZn@CMp>%7peS2M-JQc-eQrqe2N%ay|HgSOD^{2AL2YN#`+(}PL$sofD`Ab#I z`TQ~;t)n_-+H3|o1#)wm)9g5#mY?2-M2>6uNgZ(PrJ=$0+T$!8L3}FA07Scxn3%9^ z!)rvw+rE8>{DXX&ehiSAF6b6i3`aJG7YgQ+Gtb)V5)JM7f`xZ1i5m(c+wop?MI4f^z@Rs%EthlV`7NUW7k%c`6kJC;MISvYOg+*$1_M$IE(2fe z2~_GmbBoP{P3jYVoCL^K%>q5jd~p4fy-iwR!>`_KBeic3?*lz`SYoDMKhJDx{Kk>fT5h~U;4gnZE>REq z->aVfH)*wqSVpvc0}zK0M6g7L$@zJ20s;e<&C-0km7iNYW0ZdU=ufE!(t~$H2utMvO7RE>e)-@=yIx7m>|pHLlm~jNTAya0M&8m% zRpVqmmu-B+h;oZ+rz;F3%84tR$~!ZBWkkHp4{b$o-msBD5P>OZ&*{5*G)V7IrHE#e z1LXQ8$A%Ccku=$BS_7gwaS#}ywvG;ELN8JfRU4wH@b|I1l{&fFOn|t#bo@|HlXYKf zs@5~#?yde=jC7%SB=!(VF(~$a(RGjUSk4THtMo#0zgC{J>(sPL6LQt~$XYOI`eqq- zM-7_6^8=T&ak4e;G>4}o-dT`0s#%jhlx^01x0z=JS6p!Y7mXH>#S*SiXmd4DzQKtO z%T>7n<{`tj&{(x*zWY5Jgv!Pb$hG|F@tmZpmj?#IKOEIwtaD4B?lpa5z*DS~2yo`m zl_!qQvq{T~k1`{)RPnjE@p6?rcfLdDbu_et_*}H;1~@o23*TF+?Dw3qEmjc)NMi+* zB&-st_lN-Nrb?tjJe#DAjH;XucBkjJ^0Mz(fDRfqY~~}~j=@F8a5$x`%lI;K_3G8A z&v?xjn`)#=$AM_ajQpA5GzE^<2e8kOMWEi#qVM-YFDv~-A*0|Wz z)l{~Jw=l7>IZC^B_0fTyJU;k~=pWCXJYf<#w{enPB6Bgdwbc%6y~WK%1M4n6Up#g( zDC@(78KH&5Iraf#|yZj35 zDz@UhLXPSvw1aqo%K}vK`O2-NVxD4TWaPG*re_>j{uIzd*B_OJWCu71%3Z@ zzUx>f9LStjPPRL97v5m@M-Uf}yn-BB!BQqN817auLadIS6wt{`e0gEEJW6=<_eEnv zZ<-T#JkezI=PeEob8?EwEiyLO*Z^@97eJ=zgc&BC$jmul!bJ*YJ*W5Q^`;^$WPI2W zo58AiHap=qCyF{IGO6kGo&P&Jvpb#F_^Fx9cG91O00U6zJ!lAb8lrm*%BS$*f;|YMs!gSFh4d6Nw62Bw6O`fnL6t$yZKnB_+W17`mveC?Y~UWe^FX$j$zkX%+O(;my*UL=ZiKJv&?1wmB699Cg+Ld z2!=vtjp!ww^H+4Ljp$*3*G?91yp&i@8>#~InsY((sVz`DXRes5cAMu%kl^c&cD-M9 z_-!loTX_%;f3sBqtfK_~h1;pAd-x#GA^4Tfg5kYZ{a#;?PascmtD$ta8JA;xf_u<= zr)7kdQ!8{eMXH@U$HHa;!e(OTETVrPVk2s={7{uiaKA;Ai4<|oU`;vHQ=q9vB1MM= zrRlhY9+CZl5YF*s$s^(!y8d+sEQk1XicdL!57=0ievV_!_jTfb0`cWtJ{ZnUKwU7T zbzk4v3gsw>E5j=cE>vw}tZVZl0;4!Xu}oZ6_i@_A=WFiG96C_sx_7YWHlc_eV|h7v zP`y-%3AwP-r>{d-%ZwFw^I5X94+CWrBiA(&f0Q3Te*D(Cv-k1icbP*_7;?VMy9+D} zxaD0aKq1fR69LB-gC+9^=94DP==S@XHB*ss=o(^xqb)5e1{qnOW()cPu(vtCGzLYp ztUO>e1!y_5@_BBu-L#hK3PEGGXTc-NBrVy5!@WyjK7IWpgA>sgF5KhIw7xQNx_?7* zb$9y8gr?Xn0Oo`o(|t(WNOC_f0~~w?Vq{56&2rPuMs7WNMsrXfJb99JaW(H=RV|WQ zD!^Dd)G`A#UVz?4Eo8DEHW*SL&@{?OCz^}pLB?L+t_C5Nl$bhlq(7gJm$$cAec>E^ zeuMu$r#>tR@rPSr3)Y3%eQYMIom9hZwV-Yy0|$EZqrlD{8fGZPFDS7ZEwDC`wH3OA#0t{C*4Bf4SECY17kSDX+^Mm!(@fh zhkK77AK~0yL|-S!9R;b_$&uR223$yQ-LfSiu7i@&4%&H|#~-KCT=e}JDOv83MoF&H zqD2eoJ#ymM5G=l?q`eB)c~l3yzV(I!Qlk3q?iYkzp6qx18;5<+?L`n*l!o<1$3qik zsUd{{ai=d4RRvp$K=~?4!%rf1_Ad91))3zhiUAV{_8q{B&%Y#lP~;*EK7j0S@L=T~ zz}he0yzyT#hg>7*iwx^s`^pH~748$`5h9=DW8$95gual93NRTmw2W9!0bFA<021=i z>4sT^tGl{UPZSioyf8NzYZbvq4;?&xwM%ufoUiFaLI*}BvBjA3Iu-mt>O#g|kEm3Q ztL?+!n3BePX-m0w*=U?Q4_{@5^q)buvH_9lD=}>s@TBV~Z#eWt7z6Q+AwW$@A>gwt za>@W>g*^ga|3yJHZsvvAzH(fS9TV#+Sx*3vq=xf+Dv%-n5oA>(VHpku%K?iCOzCuVl+eXyaN>t|6K`A85OfJ>Ql%sD(oyU5@#mFg9Z)VRAy5o;NRK>;hvP*jI3ao=#r-E}&V0XXhE6Mw|D zcBmZ%w4^N&bO#NACqo9{*2|D;LeS37@7;R(`H;|1bREV}9>P2;u)OX$>I%xYQ&i%w z75Ai@)%R4!XHBU={|4zqBqQ7OKp#Jn0V9*Nr{9%<`QqYKVz~RheJ}WS*$N6aDzZQt zod~WFdOGZ{cLUX(OIpGdFgzBt!z5rGk%|yJM6-2n&a&P8&NrOE-Lu&-x0ciiKE_t? z!D1*&>&w09G>#ews7I{9@uU>2S+=9n49SNZWLOt}Rp0YmVpiSA+T@*Umv(Gw*<-H7 z+|LAiG!I_UR&UXm3+FRJS559_zEmqdU~uY&xyJ?{9enTAk|uf{8h#Ux&B^FG zG&^>#k$JNbO|KvNQd{eP^4o~l&G&Cpw)0#+a&1E4ho8yUf?jq1mRfQxrA}m`6nRV* z9X@izWbD{KvSUoOE+;1&$c<)Z6zi+sI9w%|iONI?laOa#?R(~XHM2WMB8n45bHkCf_U*Oz{e^4kY$RiL*6=q-9NPh8y^SA zgQ*a<>AZD+YBwzsGwy4@b(<10_s<#fyR@45WZXhWBJ%fug9Ws5t1+CucYH z&1yCCEnD>H35XqC0Dpn)#=_zv-?((IXGVJZAidc1aYz09Zj&Whfuc-{ynx(~jGoQU zb5%4d%q;8oL;6mnT4nIpXY~^^Za%15LUv3@=foTXZ!{W*eSB`p55O?CZKWAK*g+5N ziofK{hyg|4pv^mB>BUh*+V&s*|}aI2$I_w z0LizuIXBc7{-2M9H(T?f{r2Z@;IgDv(Y(9(^1;Qn2Jbc*48z;-jVOY(&wd z%_QB3yFD|qvWAb0v0BE$Xz89<{UFj#oKPs5|1AGSIpWS_>&Tpy8(P98cvbwvDq=X! z*Rrt+RYT1u&+WJF-MjZ@R(uX9f-qla7F(^LO{(AGp?7!sbuG*@MshN$1bb!G#+RIwn!EkR#%Jdyz*{R}Cj0 zn$U)Vf7etTO}T~O_03sJQyBn-O}z*+MwPFMl?T_E5Blbtgv#3*S4p z>*tyL`SXUn0p4KC>(JYf-&Q4=fl7Qa+xl$m(&Am&(euX;k{zm^i97nCLo)wEe}Zi9 z9{k1SYBQ6D<7g`CCLj^@(W8SvMTS5oQ@1bKpzT#{ZE1M};oYj<8C3YV3ij&J)m0mSxXDn6e*6mPWU|!o$vlS~eK@F0bczsuJHBf#Y?kHQny}z(% zVo_b{+xN1y(z5u^<=J9x3r6Ucvr=$Hu}DN}+PT}5qHAJD5Hm~m3X5cwVnv)ZfK8xj zZ?+zoyaW01e*^IJ>0a3}#p;RM=HzpUJ23G~e5TO3TppLGWn!`>q<(?nx%1*LNpmCQ zH~7TGS=!RX5U0BkFO5krV#G))<6Nru?|*=1tkZ$i8=x7j+P9~F(Bs-OMUzPlefI33 zm(1KpAI|mKKYi}py8w7ANLZ5b=tO{fp*Pm%+V<4Q38+6Z5fwo$??;IbI79VgxePLW z@ymfd#A-#CUHvRo<^J;Sn7lU|Kfbv{<72~G6O9RpqN$;JXBFs4YSwl5*SgH^J8+;U z@@KyMY~48DTe1~gR;UwC%%@Eg;>-X@YVB$^49z(GCe(XZk!XBU^e*Ip7X z0E5VIZ3q{uE6v~n1@P0+DG#f>VBH_k@-$p3h~$kO{gsq8$J9R*jk+`}==i+F^nt=Q z<$LNt%BbrIPz0+Yc(nCBvhoZwP03ZS18XWz))gVz?$x)iF1Z_fx9YrtCzsEjb?44} zVs!Hnmpt~;rS6U^iO19Hv$11qB!g0AQz@bE?8LPh2Y)0iKY!B4&@i7|)cz1|AADVM zWtKjXiQdD(<=vN;Yax53)dJNVeV+Z{#bNc2rKlb1VezA(>(^mkSUj=OSW~+i^OFOZ zLV<;cOI*mKrQ&`*v9gWM`+=;A8B8BFTsDUS^l57sgS?6Whn9 zsU!^K-%?niIh&J>o#r6|6Kn@nh_dF0hO?kTx;(@U4v_!V)VNC1FO$q%=rn2;qLjR5 zgX(vem?h2s+D=WwcP829phpi4%hN;ai@c&njKqeb={OIoK=SnV_m}RN7OB_Bk-s7I z7eI)%F(WfmS1*cWayjIL6bTyb{gJ53%nu*ktP9qtZ^bS~5MOE!LaquV*RyBc%^U79j=&BsCyFO64|CY|=66o^R}13D<00fug|Pb^wqDO zIrN|3=Ld3@#yt3960+#ctNKOCzGk$o6hYLaEhBU8P%8mPwdM{p2;m1XqUQ2$usjaR z29U8cyzw7b4yEfz@Ft5?;%(_y`WTkh5Sfa zIYrBq|UOpE8O<5-BRI zs~rJs9)9Z74(=NY&sF-@fSoBM)1LQN(oDH=!n>BAP@OXH5$?E$D4j%kdMMDAE!ELVRvLNTz zf1K~Dp)#SqXi4vRH#b+ZCM1i3IKNWY^&T}UfSWGMOocIR@Wd8u=ubA{g$HffPw^v) z*Im&@MOmX^I6%T?C2r8f6oh7O5XJn-Yz)Lu9m+?~*U>n)xE1Yv0t+i50R9`)JZOY0VEg-|CUH(Z^P zdG~HFUM1B!_0$B)U`!Jf2sV!}+7KX`VH(kZ=*<4};?F(vZY@Wi0{cK8pkM?__&44w z%zs=55eNK#2&RD?t&zA`ZU6apKIK{Rhsy&2;ziuY(z^hU?(Dc^08U{6u%V1yv~Ta( zA}+}N*}s`+=5gXJ3${;#Eyop7*h-$}0*V(5zY zq}`30G=BgSNt3f_n!fs--x<|YSh94f*xA;8iQeAGV(#3@=H{&ga-xp-vzr4}^GF*$ zd_OkL@JlCX;<&VF2A`VpjuT6-h~XNN3rg5KM>aAC7!n>{DNrTyA7+&JkX8g_T|N56 zq^LGRc4I3?xRH-apIqody1Mi;DkNk#jMg06Sg2@mhoO3#*S@7?IGKf#p{*lBcgBdMvsk+RlvC+9G*WeID}WrY9Ixs z%E9EF-^HXIOw^880MMnbuis?{0rw*`@d?N@i`ldHV%HU_;_;W*Ujy>=b z@t~4TD0xBafw8l)JYMQS;ONWS)OwYqPCwRD{^_)OJ)jZay4dG-ou44UEILx&y#DrD~Z&gCbR9zv5) zPbZYdC6X;Tb`^Lvh*1kBTA(IW&TDZ(;^(IV&(el;Qc>}BzQ^K54}QGtc2pp(i<^j8 z)FM?_y6psiq5Ru#n{yZ5R=La#=+cmX9q)^NS5Z-;U%xkDCA8HtHEe5Z%lY#O3Yuzf z--rK@AsxD0x#xMG>@TUxtPo}kA3t6xzfW`37eCgP478# zG?fBzF>ut%C&R?v{&lx8FQtds_ARM!-IubN1(XS0g1R75QNUolgqizg3>ZpP{MYu^ z=V2j-aHrT?G8Ih$mY*cDC!1<7WcAP7qEWG+;Uampkjedq>8F@k+VKW`^z{P?b0UC+ zrOzO_%GySrg6v^J^yB60Yieg#(6%IjReS_f?x76SqFQ%y`ZkB9L4{ABJ~cd;8U2_Y zvv*+Us5^Snu~4#$nUCZ8^{6M*M~wIuH=i&|nL!KXn!6F0UJ7&CBJS?LYhJBiA14oD zdhiL`QeCiosk=A#$g^n7HwvE+ul z^*lZD1Vzxg`*l+t&v1FUVN4N@(A%GWrjMPz;ArjyD&>5W%r-&26*2Ds%pK`WT0*<1lp; znM)XU7bPq)#OlqL1MXH0n3jg+(s_mXAA1lj4nd?gu2a?fQR(^P2!@bi#2A;B>vY+w z4?xa{cXnc`XdS7-sg~-=Zu`%T_gs~|Cb-onWM!}F1;Yae^PbaSkeY`%e`H=YX7&Xn z%`-?@G~8gBJ%z9 zHdH~rF4qpYn=NfX9r(U?KP;@3z0RF-Yk+^{i61=GkP!I4=Xy89Ar6_PPQ#5PyLqiN zuP<`wY}~CT)%U&feIc_O&{jE-Io=I#MslIwzpp`R`y~z=6eK|^N7zx&AM&sW1t;#z z0PUH@?grlf#qRh5waI;avX#%t7_@Tt?hYH;cukm+yh-pT8me(;QZn|NEe#H+KmPyM n%lo<`>{I>s@as2TswVND7`w_n(QSwV|CpOjHHk7_u=9Ta|DG5Z literal 30723 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 diff --git a/paper/paper.bib b/paper/paper.bib index 1491a18..c2bf151 100644 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -10,7 +10,7 @@ @techreport{studentreport title={Improving reproducibility of scientific software using Nix/NixOS}, author={Max Hausch and Simon Hauser}, year={2023}, - url={https://github.com/precice/nix-packages/releases/download/initial-paper-release/hauser-hausch-research-paper-cb56c9362bf1a2bd1b18873dd36c05b5a082097c.pdf}, + url={https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}, institution = {University of Stuttgart} } @article{Dalle_2012, diff --git a/paper/paper.tex b/paper/paper.tex index 0591bc3..868b606 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -37,7 +37,7 @@ %This evaluation enables us to assess the advantages and disadvantages of employing Nix to improve reproducibility in scientific software development within an HPC context. } -\keywords{Reproducibility, Nix, NixOS, Spack, EasyBuild, preCICE, HPC} +\keywords{Reproducibility, Nix, NixOS} \begin{document} \maketitle @@ -59,7 +59,7 @@ \section{Introduction} When a user then specifies to install the python3 package, for instance, a traditional package manager could yield version 3.8 today, but version 3.9 in a few months. Full reproducibility can, thus, only be achieved by storing the complete image. Altering a single dependency (e.g., by a bugfix) causes a rebuild of the image and, thus, destroys reproducibility. -There are, moreover, commercial, domain specifig solutions to achieve reproducibility, e.g., CodeOcean\footnote{\url{https://codeocean.com/}} mainly for bioinformatics or Weights and Biases\footnote{\url{https://wandb.ai/site}} for machine learning. +There are, moreover, commercial, domain specific solutions to achieve reproducibility, e.g., CodeOcean\footnote{\url{https://codeocean.com/}} mainly for bioinformatics or Weights and Biases\footnote{\url{https://wandb.ai/site}} for machine learning. With these archiving platforms, experiments can be rerun using technologies such as Docker. The platforms are closed source, however, such that the source code cannot be reviewed nor adjusted~\cite{koch2023sustainable}. @@ -67,7 +67,7 @@ \section{Introduction} Nix allows functional descriptions of dependencies up to fixed versions, thus avoiding the issue described above. Similar ideas are followed by the popular high performance computing (HPC) package managers EasyBuild~\cite{easybuil6495863} and Spack~\cite{spack7832814}. At FOSDEM 2018, Kenneth Hoste compares Spack, EasyBuild, and Nix with each other~\cite{Hoste}. -Minor deficits regarding reproducibility of Spack and EasyBuild are that they link against core system libraries, which can break independently. The Spack developers are aware of these shortcomings and are working on improvements\footnote{\url{https://github.com/spack/spack/issues/39560}}$^,$\footnote{\url{https://github.com/spack/spack/pull/42082}}. +Minor deficits regarding reproducibility of Spack and EasyBuild are that they link against core system libraries, e.g., glibc, which can break independently. The Spack developers are aware of these shortcomings and are working on improvements\footnote{\url{https://github.com/spack/spack/issues/39560}}$^,$\footnote{\url{https://github.com/spack/spack/pull/42082}}. EasyBuild, on the other hand, even has an option for linking against system libraries called \texttt{osdependencies}\footnote{\url{https://docs.easybuild.io/writing-easyconfig-files/\#dependency\_specs}}. Thus, packages need to be vetted and potentially updated prior to usage. All three solutions have in common that they rely on scientific software following best practices concerning building and packaging. Unfortunately, most legacy software projects do not do this. @@ -78,7 +78,8 @@ \section{Introduction} preCICE is a coupling library for partitioned multiphysics simulations. The ecosystem includes diverse legacy solvers, adapters, language bindings, and tutorials besides the coupling library itself making it a challenging and representative testcase. We try to build the complete ecosystem using Nix and run all tutorials. -This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. +This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. + \section{Background} @@ -134,7 +135,7 @@ \subsection{preCICE} preCICE supports a wide range of existing (Legacy) solvers. For each solver, there is typically a specific adapter: an either independent software package or simply a source code patch that integrates the preCICE API into the solver, see Fig.~\ref{fig:precice}. The preCICE library itself is implemented in C++, bindings to other languages are either supported through native bindings (C, Fortran) or through independent software packages (Python, Julia, Matlab, Fortran). Many official adapters, all bindings, the library itself, tutorials, additional tools, and the website including user documentation are collected and released in so-called preCICE distributions\footnote{\url{https://precice.org/installation-distribution.html}}. -In our case study, we target the distribution v2211.0~\cite{preciceDistribution}. To execute simulations, such as the included tutorials, requires the actual solvers next to the distribution. These are included, for example, in the preCICE VM\footnote{\url{https://precice.org/installation-vm.html}} and also part of our case study. Table \ref{table:label-distribution} lists all software packages of the case study. We try to reproducibly build all of these packages with Nix and try to run all tutorial cases. +In our case study, we target the distribution v2211.0~\cite{preciceDistribution}. To execute simulations, such as the included tutorials, the actual solvers are required besides the distribution. These are included, for example, in the preCICE VM\footnote{\url{https://precice.org/installation-vm.html}} and also part of our case study. Table \ref{table:label-distribution} lists all software packages of the case study. We try to reproducibly build all of these packages with Nix and try to run all tutorial cases. The diverse languages and diverse solver packages using various build system makes the preCICE ecosystem a challenging testcase, which is, however, representative for current research software in our experience. @@ -147,12 +148,12 @@ \subsection{preCICE} \hline \bfseries Package & \bfseries Type & \bfseries Build system & \bfseries Version \\ \hline preCICE & library & cmake & 2.5.0 \\ \hline - Fortran module & bindings & make & 9e3f405 \\ \hline - Julia bindings & bindings & julia & 2.5.0 \\ \hline - MATLAB bindings & bindings & matlab build script & 2.5.0.0 \\ \hline - Python bindings & bindings & setup.py & 2.5.0.1 \\ \hline ASTE & tooling & cmake & 3.0.0 \\ \hline Config visualizer & tooling & setup.py & 60f2165 \\ \hline + MATLAB bindings & bindings & matlab build script & 2.5.0.0 \\ \hline + Fortran module & bindings & make & 9e3f405 \\ \hline + Python bindings & bindings & setup.py & 2.5.0.1 \\ \hline + Julia bindings & bindings & julia & 2.5.0 \\ \hline preCICE-CalculiX adapter & solver + adapter & makefile & 2.20 \\ \hline Code\_Aster & solver & custom system in python & 14.6.0 \\ \hline Code\_Aster-preCICE adapter & adapter & custom system in python & ce995e0 \\ \hline @@ -177,25 +178,23 @@ \section{Results} \subsection{preCICE} -The preCICE library itself is already available in the nixpkgs repository\footnote{\url{https://github.com/NixOS/nixpkgs}}, so we do not have to package the software. +The preCICE library itself is already available in the nixpkgs repository\footnote{\url{https://github.com/NixOS/nixpkgs/blob/nixos-24.05/pkgs/development/libraries/precice/default.nix\#L41}}, so we do not have to package the software. Looking at the package definition and the preCICE source code, the library is quite easy to build and package as it uses CMake as a build system. \subsection{Tools} -The preCICE distribution includes several tools around preCICE. +The preCICE distribution includes two tools that enhance the preCICE user experience. -\subsubsection{ASTE} - -ASTE\footnote{\url{https://github.com/precice/aste}} stands for Artificial Solver Testing Environment. It is a thin wrapper around the preCICE API, which allows, for instance, testing of data mapping with real geometries. -ASTE requires VTK9\footnote{\url{https://vtk.org/}}, a visualization toolkit, which is built without python support in the nixpkgs repository to reduce compilation time. +One of the tools is ASTE\footnote{\url{https://github.com/precice/aste}}, which stands for Artificial Solver Testing Environment. It is a thin wrapper around the preCICE API, which allows, for instance, testing of data mapping with real geometries. +ASTE requires VTK\footnote{\url{https://vtk.org/}}, a visualization toolkit, which is built without python support in the nixpkgs repository to reduce compilation time. This feature is needed for ASTE, however. As already mentioned, Nix allows overriding of inputs, so in this case, we can look at the package definition of VTK. The parameter \texttt{enablePython} can simply be set to \texttt{true}. We then also need to supply the version of python, which we set to python3. -\subsubsection{Config visualizer} - -The preCICE config visualizer\footnote{\url{https://github.com/precice/config-visualizer}}, as the name suggests, visualizes preCICE configuration files. Similarly to preCICE itself, the tool is already packaged upstream. -As a python package, it is easy to handle with Nix. +The second tool is the preCICE config visualizer. +As the name suggests, it visualizes preCICE configuration files. +Similarly to preCICE itself, the tool is already packaged upstream\footnote{\url{https://github.com/NixOS/nixpkgs/blob/nixos-24.05/pkgs/tools/misc/precice-config-visualizer/default.nix\#L25}}. +This tool is easy to handle with Nix, as it is a python package. \subsection{Bindings} @@ -204,8 +203,8 @@ \subsection{Bindings} \subsubsection{MATLAB bindings} There were several attempts to package MATLAB\footnote{\url{https://de.mathworks.com/products/matlab.html}} for NixOS in the past\footnote{\url{https://github.com/NixOS/nixpkgs/issues/56887}}, yet there was no success so far. -This might be due to the fact, that MATLAB needs to be installed by running an installation wizard that downloads files during the installation process and verifies the licence. -Also, as MATLAB is not installed in the preCICE VM, we do not proceed in packaging the software. +This might be due to the fact, that MATLAB needs to be installed by running an installation wizard that downloads files during the installation process and verifies the license. +As MATLAB has some licensing issues and is also not installed in the preCICE VM, we do not proceed in packaging the software. \subsubsection{Fortran module} @@ -214,13 +213,13 @@ \subsubsection{Fortran module} \subsubsection{Python bindings} -The \texttt{pyprecice} package is already available upstream, but did not compile as it is not able to find the python module \texttt{pkgconfig}. +The \texttt{pyprecice} package is already available upstream, but does not compile as it is not able to find the python module \texttt{pkgconfig}. After adding this single dependency as an input to the package definition, the python package builds and can be used as expected. -This solution was contributed to the upstream nixpkgs repository. +This solution was contributed to the upstream nixpkgs repository\footnote{\url{https://github.com/NixOS/nixpkgs/commit/fd8962162ac21be59fc3a05fb6a250eeab6b2bec}}. \subsubsection{Julia bindings} -Julia~\cite{bezanson2017julia} support in NixOS is currently still in its early stages and cannot be declaratively be defined by Nix\footnote{\url{https://github.com/NixOS/nixpkgs/issues/20649}}. +Julia~\cite{bezanson2017julia} support in NixOS is currently still in its early stages and cannot be declaratively defined by Nix at the current state\footnote{\url{https://github.com/NixOS/nixpkgs/issues/20649}}. \subsection{Solvers and adapters} @@ -231,7 +230,7 @@ \subsubsection{CalculiX} It then builds the original code and the adapter code together, resulting in a combined binary. The Makefile also has hard-coded locations of its dependencies: SPOOLES, ARPACK, and yaml-cpp. These need to be replaced with the equivalent pkg-config calls. -Additionally, there is no install target provided by the makefile, thus the resulting binary needs to be installed manually by copying it to \texttt{\$out}. +Additionally, there is no install target provided by the makefile, thus the resulting binary needs to be installed manually by copying it to the \texttt{\$out} placeholder, which maps to the resulting store path. \subsubsection{Code\_Aster} @@ -276,18 +275,19 @@ \subsubsection{deal.II} dealii, enable3d ? false }: stdenv.mkDerivation rec { pname = "precice-dealii-adapter"; - version = "unstable-2022-09-23"; + version = "unstable-2022-09-23"; # could also be a git tag - src = fetchFromGitHub { + src = fetchFromGitHub { # Defining where to get the source from owner = "precice"; repo = "dealii-adapter"; rev = "dbb25...8367c"; sha256 = "sha256-pPQ2...2jlflgUE="; }; - nativeBuildInputs = [ cmake ]; - buildInputs = [ precice dealii ]; + nativeBuildInputs = [ cmake ]; # build-time dependencies + buildInputs = [ precice dealii ]; # run-time dependencies cmakeFlags = lib.optionals enable3d [ "-DDIM=3" ]; + # nix' default phases can be overwritten such as: installPhase = '' mkdir -p $out/bin && cp elasticity $out/bin/elasticity ''; @@ -303,7 +303,7 @@ \subsubsection{DUNE} There is an ongoing migration from autotools to CMake for DUNE, which might improve the situation in the future. Another minor issue is that the DUNE project is rather a collection of repositories than a monorepo. This means, users have to correctly clone all repositories such that the build system finds all relevant information. We clone all of the required DUNE repositories into a directory and additionally clone the DUNE-preCICE adapter into the same directory. -For the build and install process, we need to manually set the \texttt{\$DUNE\_CONTROL\_PATH} and the \texttt{\$DUNE\_PY\_DIR} environment variables. Both variables also need to be set at runtime. +For the build and install process, we need to manually set the \texttt{\$DUNE\_CONTROL\_PATH} and the \texttt{\$DUNE\_PY\_DIR} environment variables. Additionally, we need to patch the python install process because the current CMake file tries to access the internet with \texttt{pip install}, which is not allowed in Nix's sandboxed builds. The two environment variables must also be set at runtime. This can be achieved by sourcing the \texttt{set-dune-vars} script, which we provide. @@ -311,7 +311,7 @@ \subsubsection{DUNE} \subsubsection{FEniCS} FEniCS~\cite{fenics} is already packaged upstream, however, not with all features the FEniCs-preCICE adapter~\cite{Rodenberg2021} relies on, in particular PETSc support and mshr, the FEniCS mesh generator. -This is why, we need to package PETSc4py, the python bindings package of PETSc, which is not available upstream. +This is why we need to package PETSc4py, the python bindings package of PETSc, which is not available upstream. The build process uses the internal \texttt{buildPythonApplication} build tool and runs successfully once we add the option \texttt{build\_src --force} to rebuild cython code and pin the cython version to \texttt{0.29.34}~\footnote{\url{https://gitlab.com/petsc/petsc/-/issues/1359}}. We could not enable tests for PETSc4py, however, because they depend on OpenMPI and the network, which is not available within Nix's build sandbox. Afterwards, we specify PETSc4py as dependency for FEniCS and enable the PETSc support. @@ -323,7 +323,7 @@ \subsubsection{FEniCS} \subsubsection{Nutils} -The Nutils~\cite{nutils} solver can be build using \texttt{buildPythonPackage}. One test needs to be disabled, but the rest of the testsuite passes without issues. There is no dedicated Nutils-preCICE adapter, but preCICE is typically directly called from Nutils application scripts. +The Nutils~\cite{nutils} solver can be built using \texttt{buildPythonPackage}. One test needs to be disabled, but the rest of the testsuite passes without issues. There is no dedicated Nutils-preCICE adapter, but preCICE is typically directly called from Nutils application scripts. \subsubsection{OpenFOAM} @@ -332,7 +332,7 @@ \subsubsection{OpenFOAM} OpenFOAM uses its own custom build system called \texttt{wmake}, which is typically called with a \texttt{Allwmake} wrapper script. The build system sets 36 environment variables, one step at a time by checking several parameters, e.g.~the CPU architecture or the location of the source code. Also during runtime, these variables need to be set, either by a wrapper script or by manually sourcing a file inside the installation directory of OpenFOAM. For Nix, these properties are unfortunate. To compile OpenFOAM with Nix, we need to patch the shebangs\footnote{\url{https://foldoc.org/shebang}} of wmake to make it run during the build. -We also use a shell script, which exports the environment variables to the current shell session. +We also use a shell script which exports the environment variables to the current shell session. For simplicity, we hard-code all parameters, such as the processor architecture. These could be parametrized, however, based on the Nix inputs to allow for optimized builds. We use the script during the build phase to source all variables such that, for example, \texttt{OPENFOAM\_SRC\_PATH} points to the default location \texttt{/build/openfoam}. Afterwards, \texttt{./Allwmake -j -q} is sufficient to start the build. The install phase then copies the necessary files and directories to \texttt{\$out}, replaces the mock \texttt{OPENFOAM\_SRC\_PATH} by the value of \texttt{\$out}, and creates a wrapper for the \texttt{openfoam} shell script. @@ -348,15 +348,17 @@ \subsubsection{SU2} We do this in Nix' patch phase. Afterwards, \texttt{stdenv} automatically recognizes that SU2 uses autotools for building and runs the configure phase. Finally, to find the preCICE installation, we need to set the configuration flags \texttt{--with-include} and \texttt{--with-lib}. +Since preCICE distribution v202404, this adapter is replaced by a python-based solution + \subsection{preCICE VM} The current preCICE VM\footnote{\url{https://precice.org/installation-vm.html}} is built on top of Vagrant\footnote{\url{https://www.vagrantup.com/}} using Ubuntu as a base image. -When run for the first time, it further installs software, compiles programs, and clones the preCICE tutorials\footnote{\url{https://github.com/precice/tutorials/}}. -This inherently breaks reproducibility as the VM fetches files from the internet that are at this very point in time the \textit{latest} version, e.g. the \texttt{main} branch of the preCICE repository. +When provisioned for the first time, it further installs software, compiles programs, and clones the preCICE tutorials\footnote{\url{https://github.com/precice/tutorials/}}. +This inherently breaks reproducibility as the VM fetches files from the internet that are at this very point in time the \textit{latest} version, i.e. the \texttt{main} branch of the preCICE repository. Nix comes with the built-in functionality of producing qemu\footnote{\url{https://www.qemu.org/}} VM images. We use Nix to define a VM image with NixOS as a base, which can be built reproducibly. -The image contains all components of the case study and some additional custom tools that can only be seen in the official VM, such as the \texttt{preciceToPNG} command. +The image contains all components of the case study and some additional custom tools that can only be seen in the official VM\footnote{\url{https://github.com/precice/vm}}, such as the \texttt{preciceToPNG} command. Also, we generate an iso and a Vagrant VirtualBox file of the VM as additional outputs. \subsection{preCICE tutorials} @@ -366,8 +368,8 @@ \subsection{preCICE tutorials} We test inside the NixOS VM and also in an ad-hoc shell environment provided by the \texttt{nix develop} command. All tests pass except the \textit{Turek-Hron FSI3}, parts of the \textit{partitioned heat conduction}, parts of the \textit{perpendicular flap}, and the \textit{flow over heated plate steady state} cases. We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM participants of the partitioned heat conduction tutorial. The official preCICE VM uses a prebuilt version of swak4foam, but also patching the prebuilt binary did not work. -The dependency is, however, no longer required in the v202404.0 release of the distribution. -We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. +The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html#v24040}} of the preCICE distribution. +We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. The flow over heated plate steady state tutorial requires Code\_Aster. Even though we manage to package the solver, we observe a segmentation fault at runtime when the python code tries to call a Fortran subroutine -- a problem we did not manage to debug. % \begin{sloppypar} @@ -396,7 +398,7 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. -We were able to package nearly all components and run nearly all test cases showing the potential of Nix in the domain of scientific software. Many packages required workarounds, however, which might be difficult to achieve for none-experienced Nix users. +We were able to package nearly all components and run nearly all test cases showing the potential of Nix in the domain of scientific software. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \texttt{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). @@ -404,8 +406,6 @@ \section{Conclusion} Software packages that follow best practices for their programming language are also straightforward to package. The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. -This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. - \acknowledge{ We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and the support by the Stuttgart Center for Simulation Science (SimTech). } From bfdc9e9beb9fb8b6911af16a2f50ee6a8b6f5339 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Thu, 8 Aug 2024 16:26:19 +0200 Subject: [PATCH 02/22] fix(ci): Fix treefmt after upstream broke it --- .treefmt.toml => treefmt.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .treefmt.toml => treefmt.toml (100%) diff --git a/.treefmt.toml b/treefmt.toml similarity index 100% rename from .treefmt.toml rename to treefmt.toml From 6ef72557df2f245ee915c867fa7a3d8b8dccae48 Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Mon, 12 Aug 2024 09:29:07 +0200 Subject: [PATCH 03/22] feat: integrate some more feedback into paper and fix tests in fenics adapter --- paper/paper.tex | 19 ++++++++++--------- .../precice-fenics-adapter/default.nix | 17 ++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index 868b606..d93b78d 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -243,22 +243,22 @@ \subsubsection{Code\_Aster} In this file, we are able to disable the installation of the pinned dependencies and provide paths to the dependencies instead. More precisely, we disable HDF5, as it is already packaged in the upstream nixpkgs repository, even at the required version 5.1.10. -HDF5 is packaged with multiple outputs. -One package, \texttt{out}, contains the libraries and binaries and another, \texttt{dev} contains the header files, since most of the time, users installing HDF5 only need the libraries and binaries, and it helps to reduce installation size of this rather large package. Additionally, Code\_Aster requires Medfile and Scotch, which are both available upstream and can be used as dependencies. Another dependency is METIS, which partially builds. Thus, we decide to not replace it, but to fix the remainder of the build. -The issue is precisely that the \texttt{CMakeLists.txt} for the METIS programs hard-codes \texttt{link\_directories} to \path{/home/karypis/local/lib}. We unpack the METIS tarball, remove this line with sed, and repack the directory. +The issue is precisely that the \texttt{CMakeLists.txt} for the METIS programs hard-codes \texttt{link\_directories} to \path{/home/karypis/local/lib}. +We unpack the METIS tarball, remove this line with sed, and repack the directory. The remaining two dependencies, Mumps and Tfel are not available upstream and need to be packaged. -Mumps uses a Makefile and can be configured using Makefile.inc. By default, it provides a few configurations for systems such as Ubuntu. We use one of these provided configuration files to write our own custom config file. -It defines the locations for dependencies, such as Scotch, METIS, ParMETIS, or Blacs. +Mumps uses a Makefile and can be configured using Makefile.inc. +We write our own custom Makefile.inc by providing the locations for dependencies, such as Scotch, METIS, ParMETIS, or Blacs. Almost all dependencies are available upstream, but we need to recompile Scotch with additional build flags. Moreover, for packaging Blacs, which also uses a Makefile, we configure the build using a custom \texttt{Bmake.inc} file, which is used to set compiler flags, the path to MPI, and the bash installation. Tfel, on the other hand, uses CMake as build system making it easy to package it with Nix. After successfully packaging all dependencies, the build phase of Code\_Aster completes, but the installation part has another issue, which also affects new versions of Ubuntu and other distributions using a python version greater than 3.9. There is a forum post\footnote{\url{https://forum.code-aster.org/public/d/26475-problem-installing-code-aster-version-14-6/11}} without resolution, so we need to manually patch the bug. -The issue is precisely, that the custom build system does not correctly calculate the python site-packages directory. It unconditionally slices the first 3 chars from \texttt{sys.version}, which works for version 3.9.x, but not for version 3.10.x. +The issue is precisely, that the custom build system does not correctly calculate the python site-packages directory. +It unconditionally slices the first 3 chars from \texttt{sys.version}, which works for python version 3.9.x, but not for version 3.10.x. After patching, Code\_Aster successfully installed into \texttt{\$out/14.6/}, so we move around some files until we have a valid directory structure with \texttt{\$out/bin}, \texttt{\$out/lib}, providing symlinks for \texttt{\$out/14.6/} and \texttt{\$out/stable/}. \subsubsection{deal.II} @@ -319,7 +319,7 @@ \subsubsection{FEniCS} Lastly, we also package mshr, so all required features for the adapter package are now are available. Building the FEniCS-preCICE adapter is now directly possible with \texttt{buildPythonPackage}. -All but two of the adapter's tests run successfully, which means, however, that we need to disable the tests. +We then validate the correctness by including an import check as well as successfully running the full test suite. \subsubsection{Nutils} @@ -354,7 +354,8 @@ \subsection{preCICE VM} The current preCICE VM\footnote{\url{https://precice.org/installation-vm.html}} is built on top of Vagrant\footnote{\url{https://www.vagrantup.com/}} using Ubuntu as a base image. When provisioned for the first time, it further installs software, compiles programs, and clones the preCICE tutorials\footnote{\url{https://github.com/precice/tutorials/}}. -This inherently breaks reproducibility as the VM fetches files from the internet that are at this very point in time the \textit{latest} version, i.e. the \texttt{main} branch of the preCICE repository. +This means that we only have reproducibility when fetching the VM from vagrant cloud~\footnote{\url{https://app.vagrantup.com/precice/boxes/precice-vm}}, as we can not rebuild the VM from scratch, because the provision step currently fetches files from the internet that are at this very point in time the \textit{latest} version, i.e. the \texttt{main} branch of the preCICE repository rather than a pinned tag or commit. +Making us dependent on vagrant cloud to continue to serve the box. Nix comes with the built-in functionality of producing qemu\footnote{\url{https://www.qemu.org/}} VM images. We use Nix to define a VM image with NixOS as a base, which can be built reproducibly. @@ -368,7 +369,7 @@ \subsection{preCICE tutorials} We test inside the NixOS VM and also in an ad-hoc shell environment provided by the \texttt{nix develop} command. All tests pass except the \textit{Turek-Hron FSI3}, parts of the \textit{partitioned heat conduction}, parts of the \textit{perpendicular flap}, and the \textit{flow over heated plate steady state} cases. We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM participants of the partitioned heat conduction tutorial. The official preCICE VM uses a prebuilt version of swak4foam, but also patching the prebuilt binary did not work. -The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html#v24040}} of the preCICE distribution. +The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html\#v24040}} of the preCICE distribution. We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. The flow over heated plate steady state tutorial requires Code\_Aster. Even though we manage to package the solver, we observe a segmentation fault at runtime when the python code tries to call a Fortran subroutine -- a problem we did not manage to debug. diff --git a/precice-packages/precice-fenics-adapter/default.nix b/precice-packages/precice-fenics-adapter/default.nix index 5a1aa14..7427e35 100644 --- a/precice-packages/precice-fenics-adapter/default.nix +++ b/precice-packages/precice-fenics-adapter/default.nix @@ -1,6 +1,6 @@ { lib, - fetchPypi, + fetchFromGitHub, python3, precice, fenics, @@ -14,10 +14,11 @@ python3.pkgs.buildPythonPackage rec { pname = "precice-fenics-adapter"; version = "1.4.0"; - src = fetchPypi { - pname = "fenicsprecice"; - inherit version; - hash = "sha256-ux5qi4SGGHETbldfEiT8H/7Pvmn2uvQwDFB1wi/pAKI="; + src = fetchFromGitHub { + owner = "precice"; + repo = "fenics-adapter"; + rev = "v${version}"; + hash = "sha256-tddOcFZ/ls6fV+prtHQSIJmJ04eU9voj7ZyXEzEU6fA="; }; nativeBuildInputs = [ @@ -33,10 +34,8 @@ python3.pkgs.buildPythonPackage rec { fenics-mshr python3.pkgs.scipy ]; - checkInputs = with python3.pkgs; [ pytest ]; - - # TODO(conni2461): Remove once (two tests still fail - doCheck = false; + pythonImportsCheck = [ "fenicsprecice" ]; + nativeCheckInputs = with python3.pkgs; [ pytest ]; DIJITSO_CACHE_DIR = "/tmp"; From 17bfbb560370f814e35feb11a5380cb2509bbcd5 Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Tue, 13 Aug 2024 08:27:34 +0200 Subject: [PATCH 04/22] feat: more feedback --- paper/paper.tex | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index d93b78d..2e9a5e3 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -78,10 +78,13 @@ \section{Introduction} preCICE is a coupling library for partitioned multiphysics simulations. The ecosystem includes diverse legacy solvers, adapters, language bindings, and tutorials besides the coupling library itself making it a challenging and representative testcase. We try to build the complete ecosystem using Nix and run all tutorials. -This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. - +In section~\ref{sec:background} the background to Nix and preCICE is introduced, section~\ref{sec:results} presents the case study on packaging the preCICE ecosystem including its challenges and workarounds. +After this we discuss the results in section~\ref{sec:discussion}, followed by the conclusion of this paper in section~\ref{sec:conclusion}. +This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. +Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. \section{Background} +\label{sec:background} This chapter gives a short introduction into Nix and preCICE. @@ -172,6 +175,7 @@ \subsection{preCICE} \section{Results} +\label{sec:results} We present challenges, solutions, and workarounds for packaging all components of the preCICE ecosystem. The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}}. @@ -377,6 +381,7 @@ \subsection{preCICE tutorials} % \end{sloppypar} \section{Discussion} +\label{sec:discussion} After detailing the challenges of building and packaging all components of the preCICE ecosystem and running the tutorials as testcases, we want to discuss common points between these scientific software packages. The required effort to package the individual components varies drastically. Major problems can be traced back to the build system. @@ -389,13 +394,16 @@ \section{Discussion} If a package supports all policies, they can be added to the growing list of packages in xSDK. It is no surprise that xSDK packages (e.g., PETSc, deal.II, or preCICE) are also easy to package with Nix. -The xSDK policies also requires portable installations. Several components in the preCICE ecosystem require installation into \texttt{\$HOME} or any required files to be located at specific locations. Both, the CalculiX-preCICE adapter and the SU2-preCICE adapter require the original source code to be present as they add new features on top or patch the source code. -The current solution of cloning the code at the specific location works, but it might be better to look into Git submodules. This would moreover allow pinning the version of the original code compared to only documenting it. +The xSDK policies also requires portable installations. Several components in the preCICE ecosystem require installation into \texttt{\$HOME} or any required files to be located at specific locations. +Both, the CalculiX-preCICE adapter and the SU2-preCICE adapter require the original source code to be present as they add new features on top or patch the source code. +The current solution that these build systems require cloning the code to a specific directory works, but it might be better to look into Git submodules, as this would result in a more portable solution. +This would moreover allow pinning the version of the original code compared to only documenting it. Finally, hard-coding libraries to \texttt{/usr/lib} and \texttt{/usr/include} might work on one system, but might make it hard or even impossible to install a package on a different system. Configurable solutions, such as \texttt{pkg-config}, should always be preferred and work out of the box with common paths such as \texttt{/usr/lib}. \section{Conclusion} +\label{sec:conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. From 31904068c24e153c894e3eb8c957003aaa9e3964 Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Tue, 13 Aug 2024 09:22:20 +0200 Subject: [PATCH 05/22] chore: fix ci --- .hydra/default.nix | 8 +++++--- .hydra/release.nix | 29 ++++++++++++++++++----------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.hydra/default.nix b/.hydra/default.nix index 37597bf..f6e1624 100644 --- a/.hydra/default.nix +++ b/.hydra/default.nix @@ -1,4 +1,5 @@ -{ declInput, projectName, ... }: let +{ declInput, projectName, ... }: +let jobsets = { flakeJobset = { enabled = 1; @@ -11,10 +12,11 @@ enableemail = false; emailoverride = ""; keepnr = 3; - inputs = {}; + inputs = { }; }; }; -in { +in +{ jobsets = derivation { name = "forschungsprojekt-spec.json"; system = builtins.currentSystem; diff --git a/.hydra/release.nix b/.hydra/release.nix index ffea4cb..a00fe2b 100644 --- a/.hydra/release.nix +++ b/.hydra/release.nix @@ -12,20 +12,27 @@ let names = builtins.attrNames ((builtins.elemAt precicePkgs 1) { } { }); # Generate attrs in form `packagename = pkgs.packagename;` - packages = builtins.listToAttrs (builtins.map (name: { inherit name; value = pkgs."${name}"; }) names); + packages = builtins.listToAttrs ( + builtins.map (name: { + inherit name; + value = pkgs."${name}"; + }) names + ); # $ NIXOS_CONFIG=$PWD/configuration.nix nix repl '' # nix-repl> config.system.build.vm # vm = (pkgs.nixos { configuration}).config.system.build.vm - inherit ((import { - modules = [ - ../configuration.nix - { - nixpkgs.pkgs = pkgs; - } - ]; - }).config.system.build) vm; + inherit + ((import { + modules = [ + ../configuration.nix + { nixpkgs.pkgs = pkgs; } + ]; + }).config.system.build + ) + vm + ; in - # These are the separate jobs that are generated - packages // { inherit vm; } +# These are the separate jobs that are generated +packages // { inherit vm; } From ddf824ae6cded15cf06c401587c1e2cf706eb1a3 Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Tue, 13 Aug 2024 11:03:33 +0200 Subject: [PATCH 06/22] feat: push remaining feedback changes --- paper/paper.bib | 2 +- paper/paper.tex | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/paper/paper.bib b/paper/paper.bib index c2bf151..db2f253 100644 --- a/paper/paper.bib +++ b/paper/paper.bib @@ -10,7 +10,7 @@ @techreport{studentreport title={Improving reproducibility of scientific software using Nix/NixOS}, author={Max Hausch and Simon Hauser}, year={2023}, - url={https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}, + url={https://github.com/precice/nix-packages/releases/tag/initial-paper-release}, institution = {University of Stuttgart} } @article{Dalle_2012, diff --git a/paper/paper.tex b/paper/paper.tex index 2e9a5e3..2f9778e 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -407,7 +407,9 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. -We were able to package nearly all components and run nearly all test cases showing the potential of Nix in the domain of scientific software. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. +Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselfs, four were already packaged upstream and two were not packageable as described earlier. +Additionally we were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials, showing the potential of Nix in the domain of scientific software. +Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \texttt{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). From 85e17c0d5d9d319f80093668904cee3bf7f56e08 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Tue, 13 Aug 2024 15:51:16 +0200 Subject: [PATCH 07/22] feat: Add MIT license --- paper/LICENSE | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 paper/LICENSE diff --git a/paper/LICENSE b/paper/LICENSE new file mode 100644 index 0000000..012d6b1 --- /dev/null +++ b/paper/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024 preCICE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + From e84f348af529420705926b00ee9bde8132202cff Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Wed, 14 Aug 2024 09:24:09 +0200 Subject: [PATCH 08/22] feat: integrate last feedback --- paper/paper.tex | 52 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index 2f9778e..2295484 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -98,19 +98,23 @@ \subsection{Nix}\label{sec:nix} \begin{figure} \centering \includegraphics[width=1\textwidth]{figures/coreutils.png} - \caption{The dependency graph of the coreutils package, generated by \texttt{nix-store --query --graph \$(nix build nixpkgs\#coreutils --print-out-paths) | dot -Tpng -Grankdir=LR -ocoreutils.png}} + \caption{The full dependency graph of the coreutils package, generated by \texttt{nix-store --query --graph \$(nix build nixpkgs\#coreutils --print-out-paths) | dot -Tpng -Grankdir=LR -ocoreutils.png}} \label{fig:nix-graph} \end{figure} As Nix is purely functional, it relies on functions that, without side-effects, realize the package derivations. -Inputs of these functions are parameters such as the package version or the location of the source code. +Inputs of these functions are parameters such as the package version, the location of the source code and its dependencies. +Nix then offers built-in functions for common buildsystems and languages such as cmake, rust, go and python by implementing different phases. +There are a wide range of phases that always get executed in the same order and package maintainers can then decide weather the default phase is sufficient or needs to be overriden in order to produce a working build. +The most common phases to override are the \texttt{configurePhase}, which is mostly used for cmake or autotools configuration, the \texttt{buildPhase}, \texttt{installPhase} and the \texttt{checkPhase} which can for example be used to run unit tests. +It is also worth mentioning that most phases have a pre and post step, which users can use to do slight adjustments when they need to override excisting packages. Evaluating these functions with the same inputs yields the same outputs. This is a critical factor for Nix's reproducibility. Outputs, i.e. the build artifacts, never change after being built once. Nix builds are, moreover, sandboxed, meaning that there is no internet access possible during a build. All contents, including source files and resulting build artifacts, are stored inside the Nix store. -Per default, the Nix store resides in the path \texttt{/nix/store} on the file system. +Per default, the Nix store resides in the path \path{/nix/store} on the file system. The naming scheme for packages includes the above mentioned hash, for preCICE v2.5.0, for example, \path{/nix/store/0a5gw3l...-precice-2.5.0}. This eases checking the Nix store for integrity and ensures that builds using the same inputs are performed only once. @@ -131,7 +135,7 @@ \subsection{preCICE} \begin{figure} \centering \includegraphics[width=0.5\textwidth]{figures/precice.png} - \caption{Software setup of preCICE from the preCICE website \url{https://precice.org}} + \caption{Software setup of preCICE from the preCICE website \url{https://precice.org}. It shows how a custom solver can be coupled using an adapter with existing adapters for OpenFOAM and CalculiX.} \label{fig:precice} \end{figure} @@ -177,8 +181,12 @@ \subsection{preCICE} \section{Results} \label{sec:results} -We present challenges, solutions, and workarounds for packaging all components of the preCICE ecosystem. -The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}}. +In this section we will look and discuss all components within the preCICE ecosystem. +We then present challenges, solutions and workarounds that occur when packaging these components. +This section is structured as follows, we first look into preCICE itself, followed by additional tooling and bindings of the preCICE library in other languages. +Afterwards we present solutions for all solvers and their respected adapters. +Lastly we show that Nix additionally be utilized to generate iso files as well as qemu and Vagrant VM images. +The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}} and can be used to download and run any of the presented packages. \subsection{preCICE} @@ -217,7 +225,7 @@ \subsubsection{Fortran module} \subsubsection{Python bindings} -The \texttt{pyprecice} package is already available upstream, but does not compile as it is not able to find the python module \texttt{pkgconfig}. +The pyprecice package is already available upstream, but does not compile as it is not able to find the python module pkgconfig. After adding this single dependency as an input to the package definition, the python package builds and can be used as expected. This solution was contributed to the upstream nixpkgs repository\footnote{\url{https://github.com/NixOS/nixpkgs/commit/fd8962162ac21be59fc3a05fb6a250eeab6b2bec}}. @@ -253,7 +261,7 @@ \subsubsection{Code\_Aster} We unpack the METIS tarball, remove this line with sed, and repack the directory. The remaining two dependencies, Mumps and Tfel are not available upstream and need to be packaged. -Mumps uses a Makefile and can be configured using Makefile.inc. +Mumps uses a Makefile and can be configured using \texttt{Makefile.inc}. We write our own custom Makefile.inc by providing the locations for dependencies, such as Scotch, METIS, ParMETIS, or Blacs. Almost all dependencies are available upstream, but we need to recompile Scotch with additional build flags. Moreover, for packaging Blacs, which also uses a Makefile, we configure the build using a custom \texttt{Bmake.inc} file, which is used to set compiler flags, the path to MPI, and the bash installation. @@ -275,8 +283,11 @@ \subsubsection{deal.II} \begin{figure*} \normalsize \begin{minted}{nix} -{ lib, stdenv, fetchFromGitHub, cmake, precice, - dealii, enable3d ? false }: +{ + # Inputs including nix functions/packages or additional flags + lib, stdenv, fetchFromGitHub, cmake, dealii, + # Optional features that users can enable when overriding + enable3d ? false }: stdenv.mkDerivation rec { pname = "precice-dealii-adapter"; version = "unstable-2022-09-23"; # could also be a git tag @@ -286,13 +297,18 @@ \subsubsection{deal.II} rev = "dbb25...8367c"; sha256 = "sha256-pPQ2...2jlflgUE="; }; - nativeBuildInputs = [ cmake ]; # build-time dependencies - buildInputs = [ precice dealii ]; # run-time dependencies + # dependencies only available at build-time + nativeBuildInputs = [ cmake ]; + # dependencies that also need to be installed at run-time + # mostly libraries needed for linking and for execution + buildInputs = [ precice dealii ]; cmakeFlags = lib.optionals enable3d [ "-DDIM=3" ]; # nix' default phases can be overwritten such as: installPhase = '' + # $out contains the final path inside the nix store. + # The resulting build files are copied into this directory mkdir -p $out/bin && cp elasticity $out/bin/elasticity ''; } @@ -316,7 +332,7 @@ \subsubsection{FEniCS} FEniCS~\cite{fenics} is already packaged upstream, however, not with all features the FEniCs-preCICE adapter~\cite{Rodenberg2021} relies on, in particular PETSc support and mshr, the FEniCS mesh generator. This is why we need to package PETSc4py, the python bindings package of PETSc, which is not available upstream. -The build process uses the internal \texttt{buildPythonApplication} build tool and runs successfully once we add the option \texttt{build\_src --force} to rebuild cython code and pin the cython version to \texttt{0.29.34}~\footnote{\url{https://gitlab.com/petsc/petsc/-/issues/1359}}. +The build process uses the internal \texttt{buildPythonApplication} build tool and runs successfully once we add the option \texttt{build\_src --force} to rebuild cython code and pin the cython version to 0.29.34~\footnote{\url{https://gitlab.com/petsc/petsc/-/issues/1359}}. We could not enable tests for PETSc4py, however, because they depend on OpenMPI and the network, which is not available within Nix's build sandbox. Afterwards, we specify PETSc4py as dependency for FEniCS and enable the PETSc support. Additionally, we need to recompile PETSc with additional features enabled that are not enabled by the upstream Nix package. These include ParMETIS, HYPRE and ScaLAPACK. We use \texttt{overrideAttrs}, a Nix feature that allows us to change an existing package. @@ -333,7 +349,7 @@ \subsubsection{OpenFOAM} The preCICE-OpenFOAM adapter~\cite{OpenFOAMpreCICE} supports multiple flavors of OpenFOAM. We restrict our analysis to the OpenFOAM fork of OpenCFD Ltd\footnote{\url{https://www.openfoam.com/}}. -OpenFOAM uses its own custom build system called \texttt{wmake}, which is typically called with a \texttt{Allwmake} wrapper script. +OpenFOAM uses its own custom build system called wmake, which is typically called with a Allwmake wrapper script. The build system sets 36 environment variables, one step at a time by checking several parameters, e.g.~the CPU architecture or the location of the source code. Also during runtime, these variables need to be set, either by a wrapper script or by manually sourcing a file inside the installation directory of OpenFOAM. For Nix, these properties are unfortunate. To compile OpenFOAM with Nix, we need to patch the shebangs\footnote{\url{https://foldoc.org/shebang}} of wmake to make it run during the build. We also use a shell script which exports the environment variables to the current shell session. @@ -358,7 +374,7 @@ \subsection{preCICE VM} The current preCICE VM\footnote{\url{https://precice.org/installation-vm.html}} is built on top of Vagrant\footnote{\url{https://www.vagrantup.com/}} using Ubuntu as a base image. When provisioned for the first time, it further installs software, compiles programs, and clones the preCICE tutorials\footnote{\url{https://github.com/precice/tutorials/}}. -This means that we only have reproducibility when fetching the VM from vagrant cloud~\footnote{\url{https://app.vagrantup.com/precice/boxes/precice-vm}}, as we can not rebuild the VM from scratch, because the provision step currently fetches files from the internet that are at this very point in time the \textit{latest} version, i.e. the \texttt{main} branch of the preCICE repository rather than a pinned tag or commit. +This means that we only have reproducibility when fetching the VM from vagrant cloud~\footnote{\url{https://app.vagrantup.com/precice/boxes/precice-vm}}, as we can not rebuild the VM from scratch, because the provision step currently fetches files from the internet that are at this very point in time the \textit{latest} version, i.e. the main branch of the preCICE repository rather than a pinned tag or commit. Making us dependent on vagrant cloud to continue to serve the box. Nix comes with the built-in functionality of producing qemu\footnote{\url{https://www.qemu.org/}} VM images. @@ -399,8 +415,8 @@ \section{Discussion} The current solution that these build systems require cloning the code to a specific directory works, but it might be better to look into Git submodules, as this would result in a more portable solution. This would moreover allow pinning the version of the original code compared to only documenting it. -Finally, hard-coding libraries to \texttt{/usr/lib} and \texttt{/usr/include} might work on one system, but might make it hard or even impossible to install a package on a different system. -Configurable solutions, such as \texttt{pkg-config}, should always be preferred and work out of the box with common paths such as \texttt{/usr/lib}. +Finally, hard-coding libraries to \path{/usr/lib} and \path{/usr/include} might work on one system, but might make it hard or even impossible to install a package on a different system. +Configurable solutions, such as pkg-config, should always be preferred and work out of the box with common paths such as \path{/usr/lib}. \section{Conclusion} \label{sec:conclusion} @@ -411,7 +427,7 @@ \section{Conclusion} Additionally we were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials, showing the potential of Nix in the domain of scientific software. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. -In fact, every piece of software has to lie within \texttt{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). +In fact, every piece of software has to lie within \path{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). Most problems, however, can be traced back to a lack of standardization in research software, especially regarding build systems. Software packages that follow best practices for their programming language are also straightforward to package. From cb37988dd314313cbf795cef23088d7c7aa805ab Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Wed, 14 Aug 2024 09:44:25 +0200 Subject: [PATCH 09/22] chore: fix some typos --- paper/paper.tex | 53 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index 2295484..b79a3ef 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -4,7 +4,6 @@ \usepackage{subfig} \usepackage{xcolor} -%\newcommand\todo[1]{\textcolor{red}{TODO #1}} \input{frontmatter} @@ -104,10 +103,10 @@ \subsection{Nix}\label{sec:nix} As Nix is purely functional, it relies on functions that, without side-effects, realize the package derivations. Inputs of these functions are parameters such as the package version, the location of the source code and its dependencies. -Nix then offers built-in functions for common buildsystems and languages such as cmake, rust, go and python by implementing different phases. -There are a wide range of phases that always get executed in the same order and package maintainers can then decide weather the default phase is sufficient or needs to be overriden in order to produce a working build. -The most common phases to override are the \texttt{configurePhase}, which is mostly used for cmake or autotools configuration, the \texttt{buildPhase}, \texttt{installPhase} and the \texttt{checkPhase} which can for example be used to run unit tests. -It is also worth mentioning that most phases have a pre and post step, which users can use to do slight adjustments when they need to override excisting packages. +Nix then offers built-in functions for common buildsystems and languages such as CMake, Rust, Go and python by implementing different phases. +There are a wide range of phases that always get executed in the same order and package maintainers can then decide weather the default phase is sufficient or needs to be overridden in order to produce a working build. +The most common phases to override are the \texttt{configurePhase}, which is mostly used for CMake or Autotools configuration, the \texttt{buildPhase}, \texttt{installPhase} and the \texttt{checkPhase} which can for example be used to run unit tests. +It is also worth mentioning that most phases have a \texttt{pre} and \texttt{post} phases, which users can use to make slight adjustments when they need to override existing packages. Evaluating these functions with the same inputs yields the same outputs. This is a critical factor for Nix's reproducibility. Outputs, i.e. the build artifacts, never change after being built once. @@ -154,26 +153,26 @@ \subsection{preCICE} \begin{tabular}{|l|l|l|l|} \hline \bfseries Package & \bfseries Type & \bfseries Build system & \bfseries Version \\ \hline - preCICE & library & cmake & 2.5.0 \\ \hline - ASTE & tooling & cmake & 3.0.0 \\ \hline + preCICE & library & CMake & 2.5.0 \\ \hline + ASTE & tooling & CMake & 3.0.0 \\ \hline Config visualizer & tooling & setup.py & 60f2165 \\ \hline MATLAB bindings & bindings & matlab build script & 2.5.0.0 \\ \hline Fortran module & bindings & make & 9e3f405 \\ \hline Python bindings & bindings & setup.py & 2.5.0.1 \\ \hline Julia bindings & bindings & julia & 2.5.0 \\ \hline - preCICE-CalculiX adapter & solver + adapter & makefile & 2.20 \\ \hline + preCICE-CalculiX adapter & solver + adapter & Makefile & 2.20 \\ \hline Code\_Aster & solver & custom system in python & 14.6.0 \\ \hline Code\_Aster-preCICE adapter & adapter & custom system in python & ce995e0 \\ \hline - deal.II & solver & cmake & 9.4.1 \\ \hline - preCICE-deal.II adapter & adapter & cmake & dbb25bea \\ \hline + deal.II & solver & CMake & 9.4.1 \\ \hline + preCICE-deal.II adapter & adapter & CMake & dbb25bea \\ \hline DUNE-FEM & solver library & setup.py & 2.8.0 \\ \hline - preCICE-DUNE adapter& adapter & scripts + cmake & 5f2364d \\ \hline - FEniCS & solver library& cmake + setup.py & 2019.1.0 \\ \hline + preCICE-DUNE adapter& adapter & scripts + CMake & 5f2364d \\ \hline + FEniCS & solver library& CMake + setup.py & 2019.1.0 \\ \hline preCICE-FEniCS adapter & adapter & setup.py & 1.4.0 \\ \hline Nutils & solver library & setup.py & 7.0.0 \\ \hline OpenFOAM & solver & wmake/Allwmake & 2206 \\ \hline preCICE-OpenFOAM adapter & adapter & wmake/Allwmake & 1.2.1 \\ \hline - preCICE-SU2 adapter & solver + adapter & patch script + autoconf & 6.0.0 \\ \hline + preCICE-SU2 adapter & solver + adapter & patch script + Autoconf & 6.0.0 \\ \hline \end{tabular} \end{table} @@ -216,7 +215,7 @@ \subsubsection{MATLAB bindings} There were several attempts to package MATLAB\footnote{\url{https://de.mathworks.com/products/matlab.html}} for NixOS in the past\footnote{\url{https://github.com/NixOS/nixpkgs/issues/56887}}, yet there was no success so far. This might be due to the fact, that MATLAB needs to be installed by running an installation wizard that downloads files during the installation process and verifies the license. -As MATLAB has some licensing issues and is also not installed in the preCICE VM, we do not proceed in packaging the software. +As MATLAB has some licensing issues and is also not installed in the preCICE VM, we do not proceed in packaging the preCICE bindings for the language. \subsubsection{Fortran module} @@ -237,12 +236,12 @@ \subsection{Solvers and adapters} \subsubsection{CalculiX} -The preCICE adapter for the structural mechanics code CalculiX~\cite{Uekermann2017_Adapters} requires the original CalculiX source code and provides a new makefile in the adapter repository. -By default, this makefile expects the source code to reside in \texttt{\$HOME}, but it is possible to override this location with a make variable. +The preCICE adapter for the structural mechanics code CalculiX~\cite{Uekermann2017_Adapters} requires the original CalculiX source code and provides a new Makefile in the adapter repository. +By default, this Makefile expects the source code to reside in \texttt{\$HOME}, but it is possible to override this location with a make variable. It then builds the original code and the adapter code together, resulting in a combined binary. The Makefile also has hard-coded locations of its dependencies: SPOOLES, ARPACK, and yaml-cpp. These need to be replaced with the equivalent pkg-config calls. -Additionally, there is no install target provided by the makefile, thus the resulting binary needs to be installed manually by copying it to the \texttt{\$out} placeholder, which maps to the resulting store path. +Additionally, there is no install target provided by the Makefile, thus the resulting binary needs to be installed manually by copying it to the \texttt{\$out} placeholder, which maps to the resulting store path. \subsubsection{Code\_Aster} @@ -262,7 +261,7 @@ \subsubsection{Code\_Aster} The remaining two dependencies, Mumps and Tfel are not available upstream and need to be packaged. Mumps uses a Makefile and can be configured using \texttt{Makefile.inc}. -We write our own custom Makefile.inc by providing the locations for dependencies, such as Scotch, METIS, ParMETIS, or Blacs. +We write our own custom \texttt{Makefile.inc} by providing the locations for dependencies, such as Scotch, METIS, ParMETIS, or Blacs. Almost all dependencies are available upstream, but we need to recompile Scotch with additional build flags. Moreover, for packaging Blacs, which also uses a Makefile, we configure the build using a custom \texttt{Bmake.inc} file, which is used to set compiler flags, the path to MPI, and the bash installation. Tfel, on the other hand, uses CMake as build system making it easy to package it with Nix. @@ -320,12 +319,12 @@ \subsubsection{deal.II} \subsubsection{DUNE} DUNE~\cite{bastian2020dune} uses a combination of CMake files and custom build scripts making the build process in Nix tedious. -There is an ongoing migration from autotools to CMake for DUNE, which might improve the situation in the future. +There is an ongoing migration from Autotools to CMake for DUNE, which might improve the situation in the future. Another minor issue is that the DUNE project is rather a collection of repositories than a monorepo. This means, users have to correctly clone all repositories such that the build system finds all relevant information. We clone all of the required DUNE repositories into a directory and additionally clone the DUNE-preCICE adapter into the same directory. For the build and install process, we need to manually set the \texttt{\$DUNE\_CONTROL\_PATH} and the \texttt{\$DUNE\_PY\_DIR} environment variables. Additionally, we need to patch the python install process because the current CMake file tries to access the internet with \texttt{pip install}, which is not allowed in Nix's sandboxed builds. -The two environment variables must also be set at runtime. +The two environment variables must also be set at run-time. This can be achieved by sourcing the \texttt{set-dune-vars} script, which we provide. \subsubsection{FEniCS} @@ -350,7 +349,7 @@ \subsubsection{OpenFOAM} The preCICE-OpenFOAM adapter~\cite{OpenFOAMpreCICE} supports multiple flavors of OpenFOAM. We restrict our analysis to the OpenFOAM fork of OpenCFD Ltd\footnote{\url{https://www.openfoam.com/}}. OpenFOAM uses its own custom build system called wmake, which is typically called with a Allwmake wrapper script. -The build system sets 36 environment variables, one step at a time by checking several parameters, e.g.~the CPU architecture or the location of the source code. Also during runtime, these variables need to be set, either by a wrapper script or by manually sourcing a file inside the installation directory of OpenFOAM. +The build system sets 36 environment variables, one step at a time by checking several parameters, e.g.~the CPU architecture or the location of the source code. Also during run-time, these variables need to be set, either by a wrapper script or by manually sourcing a file inside the installation directory of OpenFOAM. For Nix, these properties are unfortunate. To compile OpenFOAM with Nix, we need to patch the shebangs\footnote{\url{https://foldoc.org/shebang}} of wmake to make it run during the build. We also use a shell script which exports the environment variables to the current shell session. For simplicity, we hard-code all parameters, such as the processor architecture. These could be parametrized, however, based on the Nix inputs to allow for optimized builds. We use the script during the build phase to source all variables such that, for example, \texttt{OPENFOAM\_SRC\_PATH} points to the default location \texttt{/build/openfoam}. @@ -365,7 +364,7 @@ \subsubsection{SU2} The SU2-preCICE adapter~\cite{Uekermann2017_Adapters} patches and extends the original CFD code SU2~\cite{su2}. To this end, the adapter provides a script to run before the build phase. -We do this in Nix' patch phase. Afterwards, \texttt{stdenv} automatically recognizes that SU2 uses autotools for building and runs the configure phase. +We do this in Nix' patch phase. Afterwards, \texttt{stdenv} automatically recognizes that SU2 uses Autotools for building and runs the configure phase. Finally, to find the preCICE installation, we need to set the configuration flags \texttt{--with-include} and \texttt{--with-lib}. Since preCICE distribution v202404, this adapter is replaced by a python-based solution @@ -391,7 +390,7 @@ \subsection{preCICE tutorials} The official preCICE VM uses a prebuilt version of swak4foam, but also patching the prebuilt binary did not work. The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html\#v24040}} of the preCICE distribution. We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. -The flow over heated plate steady state tutorial requires Code\_Aster. Even though we manage to package the solver, we observe a segmentation fault at runtime when the python code tries to call a Fortran subroutine -- a problem we did not manage to debug. +The flow over heated plate steady state tutorial requires Code\_Aster. Even though we manage to package the solver, we observe a segmentation fault at run-time when the python code tries to call a Fortran subroutine -- a problem we did not manage to debug. % \begin{sloppypar} % \end{sloppypar} @@ -402,11 +401,11 @@ \section{Discussion} After detailing the challenges of building and packaging all components of the preCICE ecosystem and running the tutorials as testcases, we want to discuss common points between these scientific software packages. The required effort to package the individual components varies drastically. Major problems can be traced back to the build system. Custom build systems require an disproportional amount of additional work to make them runnable on any system. -OpenFOAM and Allwmake are prime examples of this issue. Package managers have to understand a whole new build system for a single package -- a fact that is often ignored when considering the trade-off between maintaining a custom build system versus pivoting to an industry standard, such as CMake or autotools. +OpenFOAM and Allwmake are prime examples of this issue. Package managers have to understand a whole new build system for a single package -- a fact that is often ignored when considering the trade-off between maintaining a custom build system versus pivoting to an industry standard, such as CMake or Autotools. Such standard build tools generally provide interfaces for dependency management and optional features. This is often better than only documenting these, since documentation needs to be kept in sync with the underlying code. The authors of xSDK\footnote{\url{https://xsdk.info/}} come to a similar conclusion. -They provide a list of package policies~\cite{xSDK2023}, which, for example, specify that packages must have an appropriate build system, which includes CMake and autoconf as examples. +They provide a list of package policies~\cite{xSDK2023}, which, for example, specify that packages must have an appropriate build system, which includes CMake and Autotools as examples. If a package supports all policies, they can be added to the growing list of packages in xSDK. It is no surprise that xSDK packages (e.g., PETSc, deal.II, or preCICE) are also easy to package with Nix. @@ -423,7 +422,7 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. -Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselfs, four were already packaged upstream and two were not packageable as described earlier. +Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream and two were not packageable as described earlier. Additionally we were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials, showing the potential of Nix in the domain of scientific software. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. @@ -431,7 +430,7 @@ \section{Conclusion} Most problems, however, can be traced back to a lack of standardization in research software, especially regarding build systems. Software packages that follow best practices for their programming language are also straightforward to package. -The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. +The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. \acknowledge{ We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and the support by the Stuttgart Center for Simulation Science (SimTech). From 01bb79ff3b3e64d736248bf5ba594bb81063e427 Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Wed, 14 Aug 2024 10:00:04 +0200 Subject: [PATCH 10/22] style: simplify phase description in section 2 --- paper/paper.tex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index b79a3ef..6aa62b4 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -104,8 +104,12 @@ \subsection{Nix}\label{sec:nix} As Nix is purely functional, it relies on functions that, without side-effects, realize the package derivations. Inputs of these functions are parameters such as the package version, the location of the source code and its dependencies. Nix then offers built-in functions for common buildsystems and languages such as CMake, Rust, Go and python by implementing different phases. -There are a wide range of phases that always get executed in the same order and package maintainers can then decide weather the default phase is sufficient or needs to be overridden in order to produce a working build. -The most common phases to override are the \texttt{configurePhase}, which is mostly used for CMake or Autotools configuration, the \texttt{buildPhase}, \texttt{installPhase} and the \texttt{checkPhase} which can for example be used to run unit tests. +Phases are bash scripts and are already predefined for each buildsystem and always execute in the same order. +Package maintainers can then decide weather the default phase is sufficient or needs to be overridden in order to produce a working package. +The most important phases are the \texttt{configurePhase}, which is mostly used for buildsystem configuration. +The \texttt{buildPhase} defines the build steps e.g., calling \texttt{make} or \texttt{cargo build}. +Afterwards the \texttt{installPhase} is executed which copies the results into the output directory. +Additionally a \texttt{checkPhase} can be enabled which can be used to run unit tests to insure that the package works as expected. It is also worth mentioning that most phases have a \texttt{pre} and \texttt{post} phases, which users can use to make slight adjustments when they need to override existing packages. Evaluating these functions with the same inputs yields the same outputs. This is a critical factor for Nix's reproducibility. From 44c5bd16074efe58a3c5ac4d365879ac8fdd0600 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Thu, 15 Aug 2024 10:19:57 +0200 Subject: [PATCH 11/22] fix(paper): typo, buildsystem -> build system, remove double space --- paper/paper.tex | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index 6aa62b4..9f6a1d1 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -103,14 +103,17 @@ \subsection{Nix}\label{sec:nix} As Nix is purely functional, it relies on functions that, without side-effects, realize the package derivations. Inputs of these functions are parameters such as the package version, the location of the source code and its dependencies. -Nix then offers built-in functions for common buildsystems and languages such as CMake, Rust, Go and python by implementing different phases. -Phases are bash scripts and are already predefined for each buildsystem and always execute in the same order. -Package maintainers can then decide weather the default phase is sufficient or needs to be overridden in order to produce a working package. -The most important phases are the \texttt{configurePhase}, which is mostly used for buildsystem configuration. +Nix then offers built-in functions for common build system and languages such as CMake, Rust, Go and python by implementing different phases. +Phases are bash scripts and are already predefined for each build system and always execute in the same order. +Package maintainers can then decide whether the default phase is sufficient or needs to be overridden in order to produce a working package. + +For building packages, the four key phases are the \texttt{configurePhase}, the \texttt{buildPhase}, the \texttt{installPhase} and the \texttt{checkPhase}. +During the \texttt{configurePhase}, the build system is configured. The \texttt{buildPhase} defines the build steps e.g., calling \texttt{make} or \texttt{cargo build}. Afterwards the \texttt{installPhase} is executed which copies the results into the output directory. Additionally a \texttt{checkPhase} can be enabled which can be used to run unit tests to insure that the package works as expected. It is also worth mentioning that most phases have a \texttt{pre} and \texttt{post} phases, which users can use to make slight adjustments when they need to override existing packages. + Evaluating these functions with the same inputs yields the same outputs. This is a critical factor for Nix's reproducibility. Outputs, i.e. the build artifacts, never change after being built once. @@ -288,7 +291,7 @@ \subsubsection{deal.II} \begin{minted}{nix} { # Inputs including nix functions/packages or additional flags - lib, stdenv, fetchFromGitHub, cmake, dealii, + lib, stdenv, fetchFromGitHub, cmake, dealii, # Optional features that users can enable when overriding enable3d ? false }: stdenv.mkDerivation rec { From f9667235c808fbebae4c4932781e2f7f626ba9f2 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Thu, 15 Aug 2024 13:13:00 +0200 Subject: [PATCH 12/22] feat(paper): Add paragraph to conclusion --- paper/paper.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/paper/paper.tex b/paper/paper.tex index 9f6a1d1..353accf 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -439,6 +439,10 @@ \section{Conclusion} Software packages that follow best practices for their programming language are also straightforward to package. The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. +Despite encountering challenges in packaging the numerous software tools, we were able to observe the adaptability of the Nix package manager and the pleasant user experience that results upon completion of the packaging process. +The results we have obtained indicate that Nix is a suitable solution for replicating identical software environments while simplifying the use and reuse of package definitions for users. +We would love to see more software being packaged for Nix, so that even difficult to install software will be accessible to researchers with ease. + \acknowledge{ We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and the support by the Stuttgart Center for Simulation Science (SimTech). } From b7cec2eb319ff09505df65666dd0918b7a9ea32a Mon Sep 17 00:00:00 2001 From: Benjamin Uekermann Date: Sun, 18 Aug 2024 18:39:25 +0200 Subject: [PATCH 13/22] Iterate on review changes --- paper/paper.tex | 57 +++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index 353accf..a44a1cf 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -77,8 +77,8 @@ \section{Introduction} preCICE is a coupling library for partitioned multiphysics simulations. The ecosystem includes diverse legacy solvers, adapters, language bindings, and tutorials besides the coupling library itself making it a challenging and representative testcase. We try to build the complete ecosystem using Nix and run all tutorials. -In section~\ref{sec:background} the background to Nix and preCICE is introduced, section~\ref{sec:results} presents the case study on packaging the preCICE ecosystem including its challenges and workarounds. -After this we discuss the results in section~\ref{sec:discussion}, followed by the conclusion of this paper in section~\ref{sec:conclusion}. +Section~\ref{sec:background} briefly introduces the background of Nix and preCICE. Section~\ref{sec:results} then presents the case study including challenges, workarounds, and open problems. +Afterwards, we discuss the results in section~\ref{sec:discussion}, followed by the conclusions in section~\ref{sec:conclusion}. This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. @@ -102,19 +102,18 @@ \subsection{Nix}\label{sec:nix} \end{figure} As Nix is purely functional, it relies on functions that, without side-effects, realize the package derivations. -Inputs of these functions are parameters such as the package version, the location of the source code and its dependencies. -Nix then offers built-in functions for common build system and languages such as CMake, Rust, Go and python by implementing different phases. -Phases are bash scripts and are already predefined for each build system and always execute in the same order. -Package maintainers can then decide whether the default phase is sufficient or needs to be overridden in order to produce a working package. - -For building packages, the four key phases are the \texttt{configurePhase}, the \texttt{buildPhase}, the \texttt{installPhase} and the \texttt{checkPhase}. -During the \texttt{configurePhase}, the build system is configured. -The \texttt{buildPhase} defines the build steps e.g., calling \texttt{make} or \texttt{cargo build}. -Afterwards the \texttt{installPhase} is executed which copies the results into the output directory. -Additionally a \texttt{checkPhase} can be enabled which can be used to run unit tests to insure that the package works as expected. -It is also worth mentioning that most phases have a \texttt{pre} and \texttt{post} phases, which users can use to make slight adjustments when they need to override existing packages. - -Evaluating these functions with the same inputs yields the same outputs. +Inputs of these functions are parameters such as the package version or the location of the source code and its dependencies. +Nix offers built-in functions for common build systems and languages, such as CMake, Rust, Go, and Python by implementing different phases. +Phases are bash scripts and are always executed in the same order. They are predefined for each build system, but can be overwritten if necessary. + +The four key phases are the configure phase, the build phase, the install phase, and the check phase. +During the configure phase, the build system is configured. +The build phase defines the build steps, such as calling \texttt{make} or \texttt{cargo build}. +Afterwards, the install phase copies the results into the output directory. +The check phase can be enabled to run any tests. +Most phases have a pre and post step, which can be uses to make adjustments. + +Evaluating these Nix functions with the same inputs yields the same outputs. This is a critical factor for Nix's reproducibility. Outputs, i.e. the build artifacts, never change after being built once. Nix builds are, moreover, sandboxed, meaning that there is no internet access possible during a build. @@ -141,7 +140,7 @@ \subsection{preCICE} \begin{figure} \centering \includegraphics[width=0.5\textwidth]{figures/precice.png} - \caption{Software setup of preCICE from the preCICE website \url{https://precice.org}. It shows how a custom solver can be coupled using an adapter with existing adapters for OpenFOAM and CalculiX.} + \caption{Software setup of preCICE from the preCICE website \url{https://precice.org}. The setup shows a custom solver coupled to OpenFOAM and CalculiX for conjugate-heat transfer (CHT) and fluid-structure interaction (FSI) simulations as an example.} \label{fig:precice} \end{figure} @@ -184,14 +183,13 @@ \subsection{preCICE} \end{table} -\section{Results} +\section{Case study} \label{sec:results} -In this section we will look and discuss all components within the preCICE ecosystem. -We then present challenges, solutions and workarounds that occur when packaging these components. -This section is structured as follows, we first look into preCICE itself, followed by additional tooling and bindings of the preCICE library in other languages. -Afterwards we present solutions for all solvers and their respected adapters. -Lastly we show that Nix additionally be utilized to generate iso files as well as qemu and Vagrant VM images. +We now study the packaging of all components of the preCICE ecosystem one by one, including challenges, solutions, and workarounds. +We first look at preCICE itself, followed by additional tooling and bindings. +Afterwards, we study all solvers and their respected adapters. +Next, we show that Nix can also be used to generate iso files as well as qemu and Vagrant VM images. Finally, we try running all preCICE tutorials. The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}} and can be used to download and run any of the presented packages. \subsection{preCICE} @@ -418,8 +416,8 @@ \section{Discussion} The xSDK policies also requires portable installations. Several components in the preCICE ecosystem require installation into \texttt{\$HOME} or any required files to be located at specific locations. Both, the CalculiX-preCICE adapter and the SU2-preCICE adapter require the original source code to be present as they add new features on top or patch the source code. -The current solution that these build systems require cloning the code to a specific directory works, but it might be better to look into Git submodules, as this would result in a more portable solution. -This would moreover allow pinning the version of the original code compared to only documenting it. +The current solution of requiring to clone the code into a specific directory works, but it might be better to look into Git submodules, as this would result in a more portable solution. +This would, moreover, allow pinning the version of the original code compared to only documenting it. Finally, hard-coding libraries to \path{/usr/lib} and \path{/usr/include} might work on one system, but might make it hard or even impossible to install a package on a different system. Configurable solutions, such as pkg-config, should always be preferred and work out of the box with common paths such as \path{/usr/lib}. @@ -429,8 +427,8 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. -Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream and two were not packageable as described earlier. -Additionally we were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials, showing the potential of Nix in the domain of scientific software. +Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream, and two were not packageable in their current state. +We were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \path{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). @@ -439,12 +437,11 @@ \section{Conclusion} Software packages that follow best practices for their programming language are also straightforward to package. The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. -Despite encountering challenges in packaging the numerous software tools, we were able to observe the adaptability of the Nix package manager and the pleasant user experience that results upon completion of the packaging process. -The results we have obtained indicate that Nix is a suitable solution for replicating identical software environments while simplifying the use and reuse of package definitions for users. -We would love to see more software being packaged for Nix, so that even difficult to install software will be accessible to researchers with ease. +Despite encountering challenges in packaging the numerous software tools, we were able to observe the adaptability of the Nix package manager. +Our results indicate that, in general, Nix is a suitable solution for reproducing software environments. \acknowledge{ -We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and the support by the Stuttgart Center for Simulation Science (SimTech). +We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and under project number 528693298, and the support by the Stuttgart Center for Simulation Science (SimTech). } From d918d52a3ff853ec84ba83635e24790c26ef968c Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Tue, 20 Aug 2024 14:25:19 +0200 Subject: [PATCH 14/22] feat: consistent naming for section --- paper/paper.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index a44a1cf..a81918a 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -78,14 +78,14 @@ \section{Introduction} The ecosystem includes diverse legacy solvers, adapters, language bindings, and tutorials besides the coupling library itself making it a challenging and representative testcase. We try to build the complete ecosystem using Nix and run all tutorials. Section~\ref{sec:background} briefly introduces the background of Nix and preCICE. Section~\ref{sec:results} then presents the case study including challenges, workarounds, and open problems. -Afterwards, we discuss the results in section~\ref{sec:discussion}, followed by the conclusions in section~\ref{sec:conclusion}. +Afterwards, we discuss the results in Section~\ref{sec:discussion}, followed by the conclusions in Section~\ref{sec:conclusion}. This paper is the result of a student research project and a streamlined version of its report~\cite{studentreport}. Beyond the content of this paper, the report also includes a detailed comparison of Nix to Spack and EasyBuild, and a discussion on how to use Nix on HPC systems. \section{Background} \label{sec:background} -This chapter gives a short introduction into Nix and preCICE. +This Section gives a short introduction into Nix and preCICE. \subsection{Nix}\label{sec:nix} From a3c80a6f3c23fee548786928f5172266eb7c7e20 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Tue, 20 Aug 2024 14:41:39 +0200 Subject: [PATCH 15/22] feat(paper): Minor revisions --- paper/paper.tex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index a81918a..0059ab8 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -106,11 +106,11 @@ \subsection{Nix}\label{sec:nix} Nix offers built-in functions for common build systems and languages, such as CMake, Rust, Go, and Python by implementing different phases. Phases are bash scripts and are always executed in the same order. They are predefined for each build system, but can be overwritten if necessary. -The four key phases are the configure phase, the build phase, the install phase, and the check phase. -During the configure phase, the build system is configured. -The build phase defines the build steps, such as calling \texttt{make} or \texttt{cargo build}. -Afterwards, the install phase copies the results into the output directory. -The check phase can be enabled to run any tests. +For building packages, the four key phases are the \texttt{configurePhase}, the \texttt{buildPhase}, the \texttt{installPhase} and the \texttt{checkPhase}. +During the \texttt{configurePhase}, the build system is configured. +The \texttt{buildPhase} defines the build steps, such as calling \texttt{make} or \texttt{cargo build}. +Afterwards, the \texttt{installPhase} copies the results into the output directory. +The \texttt{checkPhase} can be enabled to run any tests. Most phases have a pre and post step, which can be uses to make adjustments. Evaluating these Nix functions with the same inputs yields the same outputs. @@ -438,10 +438,10 @@ \section{Conclusion} The xSDK initiative defined such standardization policies for math software. Components of the preCICE ecosystem that already adhere to this standard, were among the easiest ones to package -- even though xSDK ultimately targets Spack and not Nix. Despite encountering challenges in packaging the numerous software tools, we were able to observe the adaptability of the Nix package manager. -Our results indicate that, in general, Nix is a suitable solution for reproducing software environments. +Our results indicate that, in general, Nix is a suitable solution for reproducing software environments and a viable solution to package management in a scientific domain. \acknowledge{ -We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and under project number 528693298, and the support by the Stuttgart Center for Simulation Science (SimTech). +We thankfully acknowledge the funding by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy EXC 2075 -- 390740016 and under project number 528693298, and the support by the Stuttgart Center for Simulation Science (SimTech). } From cd3f57c7823d3769ffbee777caf4da4052ba01a8 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Tue, 20 Aug 2024 14:55:19 +0200 Subject: [PATCH 16/22] fix(paper): There are 60 participant cases --- paper/paper.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.tex b/paper/paper.tex index 0059ab8..d8dcc36 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -428,7 +428,7 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream, and two were not packageable in their current state. -We were able to run 52 participant examples out of the 61 total examples found in the preCICE tutorials. +We were able to run 52 participant examples out of the 60 total examples found in the preCICE tutorials. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \path{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). From e781a8eb7680a3afe7bb4b33f87ad865afe4882b Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Tue, 20 Aug 2024 17:11:53 +0200 Subject: [PATCH 17/22] feat(paper): Make Nix' phases consistent --- paper/paper.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index d8dcc36..11bd0ac 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -224,7 +224,7 @@ \subsubsection{MATLAB bindings} \subsubsection{Fortran module} -We were able to package the Fortran module of preCICE by providing custom phases for the build phase and the install phase of Nix. +We were able to package the Fortran module of preCICE by providing custom contents for the \texttt{buildPhase} and the \texttt{installPhase} of Nix. The resulting binary could run the example that comes with the module. \subsubsection{Python bindings} @@ -271,7 +271,7 @@ \subsubsection{Code\_Aster} Moreover, for packaging Blacs, which also uses a Makefile, we configure the build using a custom \texttt{Bmake.inc} file, which is used to set compiler flags, the path to MPI, and the bash installation. Tfel, on the other hand, uses CMake as build system making it easy to package it with Nix. -After successfully packaging all dependencies, the build phase of Code\_Aster completes, but the installation part has another issue, which also affects new versions of Ubuntu and other distributions using a python version greater than 3.9. +After successfully packaging all dependencies, the \texttt{buildPhase} of Code\_Aster completes, but the installation part has another issue, which also affects new versions of Ubuntu and other distributions using a python version greater than 3.9. There is a forum post\footnote{\url{https://forum.code-aster.org/public/d/26475-problem-installing-code-aster-version-14-6/11}} without resolution, so we need to manually patch the bug. The issue is precisely, that the custom build system does not correctly calculate the python site-packages directory. It unconditionally slices the first 3 chars from \texttt{sys.version}, which works for python version 3.9.x, but not for version 3.10.x. @@ -357,9 +357,9 @@ \subsubsection{OpenFOAM} The build system sets 36 environment variables, one step at a time by checking several parameters, e.g.~the CPU architecture or the location of the source code. Also during run-time, these variables need to be set, either by a wrapper script or by manually sourcing a file inside the installation directory of OpenFOAM. For Nix, these properties are unfortunate. To compile OpenFOAM with Nix, we need to patch the shebangs\footnote{\url{https://foldoc.org/shebang}} of wmake to make it run during the build. We also use a shell script which exports the environment variables to the current shell session. -For simplicity, we hard-code all parameters, such as the processor architecture. These could be parametrized, however, based on the Nix inputs to allow for optimized builds. We use the script during the build phase to source all variables such that, for example, \texttt{OPENFOAM\_SRC\_PATH} points to the default location \texttt{/build/openfoam}. +For simplicity, we hard-code all parameters, such as the processor architecture. These could be parametrized, however, based on the Nix inputs to allow for optimized builds. We use the script during the \texttt{buildPhase} to source all variables such that, for example, \texttt{OPENFOAM\_SRC\_PATH} points to the default location \path{/build/openfoam}. Afterwards, \texttt{./Allwmake -j -q} is sufficient to start the build. -The install phase then copies the necessary files and directories to \texttt{\$out}, replaces the mock \texttt{OPENFOAM\_SRC\_PATH} by the value of \texttt{\$out}, and creates a wrapper for the \texttt{openfoam} shell script. +The \texttt{installPhase} then copies the necessary files and directories to \texttt{\$out}, replaces the mock \texttt{OPENFOAM\_SRC\_PATH} by the value of \texttt{\$out}, and creates a wrapper for the \texttt{openfoam} shell script. The preCICE-OpenFOAM adapter is an OpenFOAM function object, requiring OpenFOAM and wmake as build inputs. The environment variables have to be set again through the shell script mentioned above. @@ -368,8 +368,8 @@ \subsubsection{OpenFOAM} \subsubsection{SU2} The SU2-preCICE adapter~\cite{Uekermann2017_Adapters} patches and extends the original CFD code SU2~\cite{su2}. -To this end, the adapter provides a script to run before the build phase. -We do this in Nix' patch phase. Afterwards, \texttt{stdenv} automatically recognizes that SU2 uses Autotools for building and runs the configure phase. +To this end, the adapter provides a script to run before the \texttt{buildPhase}. +We do this in Nix' \texttt{patchPhase}, which is responsible for patching the source before running the \texttt{buildPhase}. Afterwards, \texttt{stdenv} automatically recognizes that SU2 uses Autotools for building and runs the \texttt{configurePhase}. Finally, to find the preCICE installation, we need to set the configuration flags \texttt{--with-include} and \texttt{--with-lib}. Since preCICE distribution v202404, this adapter is replaced by a python-based solution From 9c33b9d1d0faee1950b56bdc08e9d253bd7e7833 Mon Sep 17 00:00:00 2001 From: Benjamin Uekermann Date: Tue, 20 Aug 2024 18:09:01 +0200 Subject: [PATCH 18/22] Fix spelling mistake (Section) --- paper/paper.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.tex b/paper/paper.tex index 11bd0ac..e5486ce 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -85,7 +85,7 @@ \section{Introduction} \section{Background} \label{sec:background} -This Section gives a short introduction into Nix and preCICE. +This section gives a short introduction into Nix and preCICE. \subsection{Nix}\label{sec:nix} From b8bbd579184e3b652a799090825c4f50ba3f2660 Mon Sep 17 00:00:00 2001 From: Max Hausch Date: Tue, 20 Aug 2024 22:32:27 +0200 Subject: [PATCH 19/22] feat(paper): Explain the coupled solvers --- paper/paper.tex | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index e5486ce..b8de5d9 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -389,9 +389,9 @@ \subsection{preCICE VM} \subsection{preCICE tutorials} The preCICE tutorials included in the distribution cannot only be used as reference examples on how to couple different solvers, but also to verify functionality of solver and adapter installations by executing them. -To this end, we execute all 23 tutorials of the distribution such that each participant option is at least run once. We do not compare results, but only test whether the cases complete. +To this end, we execute all 23 tutorials of the distribution such that each coupled solver option is at least run once. We do not compare results, but only test whether the cases complete. We test inside the NixOS VM and also in an ad-hoc shell environment provided by the \texttt{nix develop} command. All tests pass except the \textit{Turek-Hron FSI3}, parts of the \textit{partitioned heat conduction}, parts of the \textit{perpendicular flap}, and the \textit{flow over heated plate steady state} cases. -We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM participants of the partitioned heat conduction tutorial. +We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM coupled solver participant of the partitioned heat conduction tutorial. The official preCICE VM uses a prebuilt version of swak4foam, but also patching the prebuilt binary did not work. The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html\#v24040}} of the preCICE distribution. We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. @@ -428,7 +428,8 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream, and two were not packageable in their current state. -We were able to run 52 participant examples out of the 60 total examples found in the preCICE tutorials. +In total, there are 22 tutorials in the preCICE v2211 distribution, many having several different coupled solver examples, resulting in a total of 60 coupled solver examples. +We were able to run 52 coupled solvers out of the total number found in the preCICE tutorials. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \path{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). From d48992df398e48437bf37a64bad025ccc79551aa Mon Sep 17 00:00:00 2001 From: Benjamin Uekermann Date: Wed, 21 Aug 2024 09:06:24 +0200 Subject: [PATCH 20/22] Simplify coupled solvers --- paper/paper.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index b8de5d9..cf6134c 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -391,7 +391,7 @@ \subsection{preCICE tutorials} The preCICE tutorials included in the distribution cannot only be used as reference examples on how to couple different solvers, but also to verify functionality of solver and adapter installations by executing them. To this end, we execute all 23 tutorials of the distribution such that each coupled solver option is at least run once. We do not compare results, but only test whether the cases complete. We test inside the NixOS VM and also in an ad-hoc shell environment provided by the \texttt{nix develop} command. All tests pass except the \textit{Turek-Hron FSI3}, parts of the \textit{partitioned heat conduction}, parts of the \textit{perpendicular flap}, and the \textit{flow over heated plate steady state} cases. -We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM coupled solver participant of the partitioned heat conduction tutorial. +We could not build swak4foam, an add-on to OpenFOAM, which is needed in the Turek-Hron FSI3 tutorial and the OpenFOAM solver of the partitioned heat conduction tutorial. The official preCICE VM uses a prebuilt version of swak4foam, but also patching the prebuilt binary did not work. The dependency is, however, no longer required in the v202404.0 release\footnote{\url{https://precice.org/installation-distribution.html\#v24040}} of the preCICE distribution. We could, moreover, not package the third-party solids4foam solver, which is one of many options in the perpendicular flap tutorial. @@ -428,8 +428,8 @@ \section{Conclusion} We investigated on whether Nix und NixOS are a potential solution to enable full reproducibility of research software environments. As a case study, we tried to package and test all components of the preCICE ecosystem -- a very heterogeneous set of legacy software packages, which is, however, representative for the state of research software today in our experience. Out of the 20 components of the preCICE distribution, we were able to package 14 components ourselves, four were already packaged upstream, and two were not packageable in their current state. -In total, there are 22 tutorials in the preCICE v2211 distribution, many having several different coupled solver examples, resulting in a total of 60 coupled solver examples. -We were able to run 52 coupled solvers out of the total number found in the preCICE tutorials. +In total, there are 22 tutorials in the preCICE v2211 distribution, many having several different coupled solvers, resulting in a total of 60 coupled solvers. +We were able to run 52 out of these. Many packages required workarounds, however, which might be difficult to achieve for non-experienced Nix users. Nix also comes with a few peculiarities, which complicate workarounds. In fact, every piece of software has to lie within \path{/nix/store} and each path therein is its own-isolated tree inspired by the Filesystem Hierarchy Standard (FHS). From ef215e1b5dd902e7df9a308d30e138f11d462dfa Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Wed, 21 Aug 2024 11:33:03 +0200 Subject: [PATCH 21/22] chore: migrate to lstlisting so we can diff those --- paper/paper.tex | 62 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/paper/paper.tex b/paper/paper.tex index cf6134c..225db40 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -1,10 +1,63 @@ \documentclass{eceasst} -\usepackage{minted} \usepackage{subfig} +\usepackage{listings} \usepackage{xcolor} + +\definecolor{identifiercolor}{rgb}{0,0,0} +\definecolor{keywordcolor}{HTML}{1a177d} +\definecolor{commentcolor}{HTML}{3d7a7a} +\definecolor{stringcolor}{HTML}{ba2121} +\definecolor{keywordcolor2}{HTML}{870000} +\definecolor{keywordcolor3}{HTML}{008000} +\definecolor{keywordcolor4}{HTML}{666666} +\lstdefinelanguage{Nix}{ + % Anything betweeen $ becomes LaTeX math mode + mathescape=false, + % Comments may or not include Latex commands + texcl=false, + keywords=[1]{pname,version,src,owner,rev,repo,sha256,nativeBuildInputs,buildInputs,installPhase}, + % Comments delimiters, we do turn this off for the manual + comment=[l]{\#}, + % Spaces are not displayed as a special character + showstringspaces=false, + % String delimiters + morestring=[b]", + morestring=[d]'', + % Size of tabulations + tabsize=2, + % Enables ASCII chars 128 to 255 + extendedchars=false, + % Case sensitivity + sensitive=true, + % Automatic breaking of long lines + breaklines=false, + % Default style for listings + basicstyle=\ttfamily, + % Position of captions is bottom + captionpos=b, + % flexible columns + columns=[l]fixed, + % Style for (listings') identifiers + identifierstyle={\ttfamily\color{identifiercolor}}, + % Style for declaration keywords + keywordstyle=[1]{\ttfamily\color{keywordcolor}}, + % Style for strings + stringstyle={\ttfamily\color{stringcolor}}, + % Style for comments + commentstyle={\ttfamily\color{commentcolor}}, + alsoletter={=} + %moredelim=**[is][\ttfamily\color{red}]{/&}{&/}, + morekeywords=[2]{false}, + keywordstyle=[2]{\ttfamily\color{keywordcolor2}}, + morekeywords=[3]{rec}, + keywordstyle=[3]{\ttfamily\color{keywordcolor3}}, + morekeywords=[4]{=}, + keywordstyle=[4]{\ttfamily\color{keywordcolor4}}, +}[keywords,comments,strings] + \input{frontmatter} \usepackage{pdfcomment} @@ -286,12 +339,13 @@ \subsubsection{deal.II} \begin{figure*} \normalsize - \begin{minted}{nix} + \begin{lstlisting}[language=Nix] { # Inputs including nix functions/packages or additional flags lib, stdenv, fetchFromGitHub, cmake, dealii, # Optional features that users can enable when overriding - enable3d ? false }: + enable3d ? false +}: stdenv.mkDerivation rec { pname = "precice-dealii-adapter"; version = "unstable-2022-09-23"; # could also be a git tag @@ -316,7 +370,7 @@ \subsubsection{deal.II} mkdir -p $out/bin && cp elasticity $out/bin/elasticity ''; } - \end{minted} + \end{lstlisting} \caption{Nix code to package the deal.II-preCICE adapter} \label{lst:dealii-adapter-nix} \end{figure*} From 899c812486a7efbab7ae73f892ae27043aed6acd Mon Sep 17 00:00:00 2001 From: Simon Hauser Date: Wed, 21 Aug 2024 14:48:14 +0200 Subject: [PATCH 22/22] feat: set updated link for tag --- paper/paper.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/paper.tex b/paper/paper.tex index 225db40..b9702bd 100644 --- a/paper/paper.tex +++ b/paper/paper.tex @@ -243,7 +243,7 @@ \section{Case study} We first look at preCICE itself, followed by additional tooling and bindings. Afterwards, we study all solvers and their respected adapters. Next, we show that Nix can also be used to generate iso files as well as qemu and Vagrant VM images. Finally, we try running all preCICE tutorials. -The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission}} and can be used to download and run any of the presented packages. +The Nix code for all components is available online\footnote{\url{https://github.com/precice/nix-packages/releases/tag/deRSE24-paper-submission-v2}} and can be used to download and run any of the presented packages. \subsection{preCICE}