From 315f884e983470f448f05d12c46e6ce61c31e4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20R=C3=BC=C3=9Fmann?= Date: Mon, 21 Nov 2022 15:14:08 +0000 Subject: [PATCH 01/19] Add TOL_ALAT_CHECK to kkrparams --- masci_tools/io/kkr_params.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/masci_tools/io/kkr_params.py b/masci_tools/io/kkr_params.py index 4e7dfe525..510c5514f 100644 --- a/masci_tools/io/kkr_params.py +++ b/masci_tools/io/kkr_params.py @@ -835,6 +835,8 @@ def __init__(self, **kwargs): None, '%i', False, 'Self-consistency control: Number of simple mixing steps to do before starting more aggressive mixing scheme (only has effect for IMIX>3).' ]), + ('TOL_ALAT_CHECK', + [None, '%e', False, 'Consistency check: tolerance for alat comparison (defaults to 1e-12 if not set).']), #code options ('RUNFLAG', [None, '%s', False, 'Running and test options: e.g. lmdos, GBULKtomemory, LDA+U, SIMULASA']), ('TESTFLAG', [None, '%s', False, 'Running and test options: e.g. tmatnew, noscatteringmoment']), From c0310cb9fbdffe10b861ea7637717cd57d07d269 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 29 Nov 2022 15:25:01 +0100 Subject: [PATCH 02/19] Fix summing of atom weights in HDF5Reader The add_partial_sums was broken for more than ten atom types since the pattern had no terminator -> MT:1 would be put together with MT:10, MT:11, etc. --- masci_tools/io/parsers/hdf5/recipes.py | 22 +++++++++++++++++---- masci_tools/io/parsers/hdf5/transforms.py | 24 +++++++++++++++++------ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/masci_tools/io/parsers/hdf5/recipes.py b/masci_tools/io/parsers/hdf5/recipes.py index 4f5970637..0ae3899e6 100644 --- a/masci_tools/io/parsers/hdf5/recipes.py +++ b/masci_tools/io/parsers/hdf5/recipes.py @@ -79,12 +79,16 @@ def dos_recipe_format(group: Literal['Local', 'jDOS', 'Orbcomp', 'MCD']) -> HDF5 if group == 'Local': atom_prefix = 'MT:' + weight_atom_terminator = '[spdf]' elif group == 'jDOS': atom_prefix = 'jDOS:' + weight_atom_terminator = '[spdf]' elif group == 'Orbcomp': atom_prefix = 'ORB:' + weight_atom_terminator = ',' elif group == 'MCD': atom_prefix = 'At' + weight_atom_terminator = 'NC' else: raise ValueError(f'Unknown group: {group}') @@ -97,8 +101,11 @@ def dos_recipe_format(group: Literal['Local', 'jDOS', 'Orbcomp', 'MCD']) -> HDF5 Transformation(name='get_all_child_datasets', kwargs={'ignore': 'energyGrid'}), AttribTransformation(name='add_partial_sums', attrib_name='atoms_groups', - args=(f'{atom_prefix}{{}}'.format,), - kwargs={'make_set': True}), + args=(f'{atom_prefix}{{}}{weight_atom_terminator}'.format,), + kwargs={ + 'make_set': True, + 'replace_format': f'{atom_prefix}{{}}'.format + }), Transformation(name='multiply_scalar', args=(1.0 / HTR_TO_EV,)), Transformation( name='split_array', @@ -179,12 +186,16 @@ def bands_recipe_format(group: Literal['Local', 'jDOS', 'Orbcomp', 'MCD'], simpl if group == 'Local': atom_prefix = 'MT:' + weight_atom_terminator = '[spdf]' elif group == 'jDOS': atom_prefix = 'jDOS:' + weight_atom_terminator = '[spdf]' elif group == 'Orbcomp': atom_prefix = 'ORB:' + weight_atom_terminator = ',' elif group == 'MCD': atom_prefix = 'At' + weight_atom_terminator = 'NC' else: raise ValueError(f'Unknown group: {group}') @@ -311,8 +322,11 @@ def bands_recipe_format(group: Literal['Local', 'jDOS', 'Orbcomp', 'MCD'], simpl Transformation(name='get_all_child_datasets', kwargs={'ignore': ['eigenvalues', 'kpts']}), AttribTransformation(name='add_partial_sums', attrib_name='atoms_groups', - args=(f'{atom_prefix}{{}}'.format,), - kwargs={'make_set': True}), + args=(f'{atom_prefix}{{}}{weight_atom_terminator}'.format,), + kwargs={ + 'make_set': True, + 'replace_format': f'{atom_prefix}{{}}'.format + }), Transformation(name='split_array', kwargs={'suffixes': ['up', 'down']}), Transformation(name='flatten_array') ], diff --git a/masci_tools/io/parsers/hdf5/transforms.py b/masci_tools/io/parsers/hdf5/transforms.py index 322d62fda..5d8231afa 100644 --- a/masci_tools/io/parsers/hdf5/transforms.py +++ b/masci_tools/io/parsers/hdf5/transforms.py @@ -708,6 +708,7 @@ def add_partial_sums_fixed(dataset, patterns, replace_entries=None): :returns: dataset with new entries containing the sums over entries matching the given pattern """ from collections.abc import Iterable + import re if not isinstance(dataset, dict): raise ValueError('add_partial_sums_fixed only available for dict datasets') @@ -720,7 +721,7 @@ def add_partial_sums_fixed(dataset, patterns, replace_entries=None): transformed = dataset.copy() for pattern, replace_entry in zip(patterns, replace_entries): - entries = [key for key in transformed.keys() if pattern in key] + entries = [key for key in transformed.keys() if re.match(pattern, key)] transformed[replace_entry] = sum_over_dict_entries(dataset, overwrite_dict=True, entries=entries) @@ -771,7 +772,7 @@ def shift_by_attribute(dataset, attribute_value, negative=False): @hdf5_transformation(attribute_needed=True) -def add_partial_sums(dataset, attribute_value, pattern_format, make_set=False, replace_entries=None): +def add_partial_sums(dataset, attribute_value, pattern_format, make_set=False, replace_format=None): """ Add entries to the dataset dict (Only available for dict datasets) with sums over entries containing a given pattern formatted with a attribute_value @@ -783,10 +784,13 @@ def add_partial_sums(dataset, attribute_value, pattern_format, make_set=False, r :param attribute_value: value to multiply by (attribute value passed in from `_transform_dataset`) :param pattern_format: callable returning a formatted string This will be called with every entry in the attribute_value list - :param replace_entries: list of str under which to enter the entries back + :param replace_format: callable returning a formatted string + This will be called with every entry in the attribute_value list :returns: dataset with new entries containing the sums over entries matching the given pattern """ + import re + if isinstance(attribute_value, h5py.Dataset): attribute_value = np.array(attribute_value) @@ -798,9 +802,17 @@ def add_partial_sums(dataset, attribute_value, pattern_format, make_set=False, r if make_set: attribute_value = set(attribute_value) - sum_patterns = [ - pattern_format(val) for val in attribute_value if any(pattern_format(val) in key for key in dataset.keys()) - ] + + sum_patterns = [] + replace_entries = None + if replace_format is not None: + replace_entries = [] + + for val in attribute_value: + if any(re.match(pattern_format(val), key) for key in dataset.keys()): + sum_patterns.append(pattern_format(val)) + if replace_format is not None: + replace_entries.append(replace_format(val)) return add_partial_sums_fixed(dataset, sum_patterns, replace_entries=replace_entries) From 0289ab8bebe074d2a5e61243979c9b848d5957c6 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 29 Nov 2022 15:35:50 +0100 Subject: [PATCH 03/19] Fix dos_order for specifying custom keys --- masci_tools/vis/fleur.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/masci_tools/vis/fleur.py b/masci_tools/vis/fleur.py index 30e544696..52898dd9c 100644 --- a/masci_tools/vis/fleur.py +++ b/masci_tools/vis/fleur.py @@ -480,9 +480,11 @@ def _dos_order(key): if '_up' in key: key = key.split('_up')[0] spin = 0 - else: + elif '_down' in key: key = key.split('_down')[0] spin = 1 + else: + raise ValueError('Invalid key') general = ('Total', 'INT', 'Sym') orbital_order = ('', 's', 'p', 'd', 'f') @@ -503,7 +505,7 @@ def _dos_order(key): return (spin, len(general) + index, tail, '') return (spin, len(general) + index, float('inf'), tail) - return None + return (spin, -1, -1, key) def _generate_dos_labels(dosdata, attributes, spinpol, latex=True, only_spin=None): From 2c76b176751a53062b668b5c5740de091c1fd362 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 29 Nov 2022 15:42:57 +0100 Subject: [PATCH 04/19] Fix parameter specification from label in DOS without spin suffixes --- masci_tools/vis/fleur.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/masci_tools/vis/fleur.py b/masci_tools/vis/fleur.py index 52898dd9c..488fd2503 100644 --- a/masci_tools/vis/fleur.py +++ b/masci_tools/vis/fleur.py @@ -441,9 +441,9 @@ def _process_dos_kwargs(ordered_keys, backend=None, **kwargs): params = get_plotter(backend) #TODO: This should be replaced with key.removesuffix() on python 3.9+ - ordered_keys_without_spin = [key[:len('_up') + 1] if key.endswith('_up') else key for key in ordered_keys] + ordered_keys_without_spin = [key[:-len('_up')] if key.endswith('_up') else key for key in ordered_keys] ordered_keys_without_spin = [ - key[:len('_down') + 1] if key.endswith('_down') else key for key in ordered_keys_without_spin + key[:-len('_down')] if key.endswith('_down') else key for key in ordered_keys_without_spin ] for key, value in kwargs.items(): From b0bca452da1483c2c8c8b24fa1206ac4da446b4c Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 29 Nov 2022 15:44:19 +0100 Subject: [PATCH 05/19] Add test for DOS plot with custom name --- .../spinpol_dos_custom_plot_keys.png | Bin 0 -> 48704 bytes tests/vis/test_fleur_vis.py | 27 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/files/fleur_vis/spinpol_dos_custom_plot_keys.png diff --git a/tests/files/fleur_vis/spinpol_dos_custom_plot_keys.png b/tests/files/fleur_vis/spinpol_dos_custom_plot_keys.png new file mode 100644 index 0000000000000000000000000000000000000000..b053bb4e1e4b03bb0ff299fd346b934676d26bad GIT binary patch literal 48704 zcmZ5|cRZEv|Nm|8Y-OJ)J0p9KjvXS|Tgcv<94iM|NysWA3L%7SvJ$ehclInR>v!FK zKA-O&KaclYa?ZK0`@XK%c)p&m=d0)kn#v@Ebc7HDk*KO5bsz`}0YR7s__*LVuYJPY zz#rmXiUwW}U2VO5Ej?@?4NEUKCs!{gdn<&GjfbbbtBWA72roYm;)$1+o2LXHpY#8{ zf!Ec;j!!!GAqlt$ft!k*CzM}& zAL1O7BKh}Y?oK!cJ~{k# zN{mJJpBHIy5lEz2VrC|>JQ>54E*EuMTicIfeZEZhPTJbl?7(vSVYY&d3CrE)D;aG0 zmP~Qamo93B43a*?`ljC0FJ8QOGx+4o*Fdn0FR>gN-SFi6WWV;;Ye%=kQT?T9&w-9N z^5NyyUDq1++K9wfUOwcvAG*aL<|emp8}R+@y(k1e=8NRy6c@D&r1sa2>*miBWd7o7 zYirkTed=}V6CSr{iy&YMxf3WCu=e9-Lbj-&AY~W=At*SUw|bl9fGrMwvW;&pwF}SK zST}MxtR_C$oD76qhF3d|TTR!xpZp$>O?vSn_dcuSd~Pgn+s_JX@bquJ9!l`=@sVbT zI4k7H1jD!YMCd$O1-VR=iE)$VKtP_%ZKrP4YWSUoiiU=wygUY20Jk7xlox#XhLj&a zF>d&f#(H^s6e$*@qoZ>ph>ZM{4BpX5q>|F&N~$?7bbd7DdUCegoWWpSVNmY3Z*~8* z5W(Q!ApW&$N@{9^E_Ew34B{U7J^PMhC7}rXG$DHmIy$<&?}7seR#vQlMkWCPf!dSB z*rep-VW+^$%QIIKp9!0_(cHA7`baZr~ZZ*5TNIQ>=hUVFuH;7woY*v5P z25Wbl&K?*U5w@HLf9vhVLf}Xqj2l(j#w}% zQ!p`MxIA5DZaDpw0XCAa9K1EtYe-e2f9l5%l;?o-b$St}mi5A%_^K))r^zaUxuD-9 zdSzyD&QqW3wuTL=9jM=FWITKJ440T$hM_P!fU880JDySUS?%DJZQ z%=zn-Yja$NYZI+V1_^tX7X_Qf>xhO1sq>Sigp>U)=A`uW=+ob;SdhZKd+xvu5VEq& zy{UZ4U}xTGW^IV+KY8+`xXh+CcclIRnGn!Bt{w8xx!HUpg;BMpiuL`@I z;LrGS4F})2O?Psn1HsQySLeSw!oo09yUYUCZsba3*kFQa2|(JJ+9 ztC;O}V-Hv?3nwQ*PS63t z;?k07_V1jlb372Kc|ANmE1V`iv8_^JW57?|i(ju<=*cs2dN^)w8qdeU0YRC8J9QfU z)a2x$;3$3eW`w<0vwSh#`n|dvFaK^r`F&@tt*tIuyD9o+p&eGOiq}meia&n&wo+j~ z{BGf0h6^Snbv*5vW&b(+BG7x%zVIdwPf5=bdrr_@D=VwX;Mrc@dg7ZmZ}J`!grSUG z8>wNh`Sj_Nk%`Rsi}*_>YAPy_h;k>MTkP-e_w|1vC$EbI87ZmFNrWB}J5q&O24t^@ zwW$Q0C#!5F>mWE;KrPQm=wC~X6>2d9(`)Ftu(!8|^8a4`V zdd1c4+n?#hJ#LLS2+sx|n>Ors((}{BWyuuIGzFjS{oO2ElD#@5{n&gN@I74+&-2%J zcWmjtZ5(?I<&Xs6N8vFsgeJjvs<7Dw2Ea%M+bxguGbZOG>O=4_^p}T zH+>XxJmbp@y(uax>JdNtvp&4#7#S6Xl_;X!d&i`fj8!@Q>nEFDH+Wm6q!>V4X=x{w zo!-$t{`^FUZaQGI6v`B2LRIa)dG`)?xKK-ZceZgxCPzBWfiuqi>hb~uvaOu3dG$W; z@9}Ozs#yR52?|#pPrzrN@tN^-FB>NS!Vx z$8T98k&GQ0Ye*y^g(CUXXJ;&km{DTHy*c=+|5r45U;pFoERS!T8aof)Pl`6ZOiM%G zG5&0^Jz0GMY_j6%MZh`u)1djObauc7ClA!^FLV+MvNtK;~o~iu+dTA)n09E{{fq|%95~%(qa-2%8{UyxV4WCHz3*-(oJv99qCB1p zkp+jgcvL5Ib?ynZ^5+W;Kk`=X*2Q{NdJNNhFJ(`2YfGed*~+PgTOYj+ai9+X=1l9&$q z-FHL8=?3st5F{slc>*W`wUkQV@|||agX{&rGYq`k@-vIkp5F8yjKqoch(nwfP46qq?`ZyAtp@5AQ{r!F~WvmR6H5H^XnhN1F&lF$B%iBW{wy* zZ(|5um>q765}~N>3w32P%*Tn&x=rjk3(>g)I9zkXq6)awIn(Ia*doBXPCl-Kz*a*K z4m^rR9l9JT$*ZrYT7WD$xY!ZPX!v?#W8;B|$@5a<8VQNjWHybq`rW1}r`5~Gu2cSzX8k3%ZQsd-#*+9T8w6Q1IfT@Z@yJU zT|L~atZRR%i;=eCW7A)U=M3VX`hGvDHoBi9!)X5W^tRIT8=(Z0Y;TkknBsRkqIYVS zuE9?U<+lYmQ)4*w|9E>3SfK0tD`S_|NBX9baFhwhBULgpV-j)t329RS+_L`ZYpEbG zkLdcHFGLFq3pYS;1!aQ8-Sl$rO}*unm76Rqm=y03^K!*0%;*3SR~oaD~sd(Vxw6((9&P0I)|Im3E%&FEK`9Pn`wonwuwpeWM4L<$HFGF=k{$7d$Y7gcm-&s0%hE z_2JwBL61cnrXhaR%n*yJE9hivdSR-NAnbl^3hW&A6}8 z-bFr-kEaO_5AOh(B?drP%4YZhaQ2M2kQ_0&20A({{aKRwTf>D3z#KAyrRzU@;L~r^MR%^(z`AaI<902p`5f$XeGq8394Thf zhYMqI!{tZTy{sG@KKRWAA4jL8q$~=Ln+#i7_RfV|nM$2)Rdy5=acCFl2%mY{5A15+ zyBB`)E5kLW(zcHR03RMDBoZCaXtp)i+$?6@N$d{5>Gt2J5MnL{QNbHEc zz69(DKJ<#9Q;&j-dq|`VoH)@`+Q4}&+n+78gkl*q1=V%EQXwZ#3Rz+T#nr)ku2qTtjD5scMuV@H zx(^LwwCH<&%><0*P0+wyqaBc!v z`N0?QnX$6w%NQcQ2C})QXLtH#&YTJ|hD-Ma7nn~x_n6NOPe?C$UV^~2WYF_aTYI76 z_g!fJ?rAn@qgg^?A{mbHy@1Bq{Sfe;;d)=!uB%he2Q;#jm!YzFSFJgbSMvjH&3+!t zf^hTzUr7V}5b!eam17Ah{Chl^cIayq1tn#Qi$aYZ{|)|-%b**?prjot-Cv!TJ*nIy zJr{@X;T$i7=CULC!az^q_|xmxbP>;4_;R zILSTvUJt=Ly1QN=W(VNc?ZE5*-%YOH#pqUM4vwhv zT>XbI+}!v9)c_FH+~Pj4zcf)-roTtqvGem5x7gX2Ky{+%?d@IJHRUAIa5U+7L&A&W zPk{8|;v&D}7!TkUTGV&{EmgD$Ul?Gh=QXndM4&KsrYU*<{(bA$Xv+N|bv{cF5^Fa< z*7L*B1{5A*zrPDwiezL++3if%)h@+LB4SwJ2nei<8m?!R5}4wqr%hZN@4yeA%UjTk zjflO@*9lU{16|z+P|VehTIU2G89L21F~T?oHf^bkKf}O|#V^n1uB?9l>hoJKNHvK! zZwwHo;WK+atR>56T;tLqI3N{HDtrFVHb7D94r)aI-=+V~(wo+l4H5@lHwcoYNCKrI zIapKa$rBDH|7G&jF8Dh*Bdh(z4&LMDi=!zB)x{jbATKW;e^v;pSJ)*wVyMM}PRj9S zao{UzkB`}4lKHOu`n3pxcDp#TgO+cAf$_zFsm^t(7vIS9GC zBAG=*s_N?PA5H5MU%h(w-=qFw17Sj7OZ#M8n&+OHXlRf;S7HUl3;^6yQrYOqcjKE$ zNl6%uW@X?5-CDY%MtfrkU2eO%!6$Ra%G!FPZ@iMx-ReSWqAlZGTwD+Y?ypaViHT{) z!z3_)9qjVa`;vo6Ui!UnqRP|`Adfz*$-t->cw8l9t!-$y4qwu>4|rwZ$^9pjlo8E9BG2?=p zUn)({zC%txKoAO`NNYHrWwp_iRFg0a+W}Exa(Tz7s_5QsI2v8VeX?=P(zVS!p!qd% z`GJYF_@Mh7dokh5Cp6kMRZj+4QlD-_5K#W-vbThVsR1biLt+O92a~&&qo7{D_Hc@Uus+lE^k4=0v3&Up1e=c&a3IXxDJuDZ(R}sr8iY@( zZGF%)2%##qVmj@Li7a_ayFLexa&QzYE9gGpwqs$@f}tQFPIgWvAK&%Ajlb?AhzLW> zKcjbnSq-L;b9Z25;JdEAJ{+>W>aO525HU*dzO2l5y4h*sZi!(fZZf-;Pcd!}nw*v2 zV_79N1a|hKdZXrIOpy$)z>OY(A2_Nr6xBv<*sM^wgJU{HAM1t>VA0fNy+N5^=Fcck zr8vlKcT@o~gZ0c8ZwLi&8y@T$z(xfuS|DiXppf3B76T>m?_(jl3UC(Rvm{gH#k56zc8$-|anwp{prg5nZEN$$7 zE}W%O|L_zCHtm{~(x*{yyRZ7`%7Gj?476}LRNLjcNI;L2(Zq)*>D2JP$C;Jz$c zF#$r$!ob%SePlL+D!He#H^|L6bshN-AQVqQE002fI!;pi!FX={zbHVt&4+BvbBu)L)7sr zKsvd|$P!%9F|Q7bP!Zglz7OT+myzrp$J14E4#9og8HKptL{q>Jn1!}UWE@+8;) zalD{1s+z5|$&z-7@zYf+{qf%@Dby0lT93a|2Zbu?#Ixd&k4Cs>$NnEUt z+Ig!}f7ec1SC=xVB12IaDx!y=TCf16VSJhF*_L2x8Gs)R@=X}QZp_CquM3V|;vkgM z31T^Z2te!4K(gL%!6L1l)(6NJtfKXn1_XWIisK?4$UP7jxm(*uOP1Tx1?AI!0r=A$ z;3#Yy9Pu3@Lc+Fj^N=_#nNwuzEASD0Uw-q~tv`xz{zUuokt=$ojcF(HAEyzB(2M3$ z;@kxr@*O5IL8WzrD}@m7_C-sVz|^4@Q1qa)Bz?I?B)}fXoE4{CUeFz~(qt#*d)7QKP;VuiT}m&QXqs0GxU37|reWCEc54CX@Ke*R1Y3es!g zFvP2ESG4^}C;F!F)`qd{3HCwUT3{V%1jifj;B0V|f|(saVx|c@(q#KB5~OyGItYU@ zfj+;W;B9$18C*mGa)`>|4mr8EB3_(r*EZF?vkmA_R1E7?1EwdpGDT9eH8j-0C=+x8 zhWOTXqk#6Qc-%vQuP|)C3yOC*)PQ5>;O1@@U(F2n|NZOj=U4QX-IbpzD?zRc-P!`k zP5~+7#bHi^s`A9WB|b=7&hTv&_#pyZSrN{={gS(10lo!f-Cg`J6hJ;yIU$$gRYuOS z1Dk;07jczZ#bX$ z;%5_WVlDoiKdm}7D`a+ZXiPe+MBZP~?Aa}xg_&WYSa^%0`sRwJri??w!=OkFfob=? z{-8__9v))Z^F1sWiU6((5XTFlcuaDj8vqkLaLkhNV@D!KMj4zkF`|h_5nLrJt>wSK zJuhQ(KH=nXm5ZC$*gyK`|LY1Mf$w#*CRl*V20{Tsna8Z*24Gu#C){>E0;ZKI@OY;K zFrMVsuLHg=48Y*ho=b8TUqfdW;Kp%Sktjq_ipw?f(+7r+u)Y=FfhJ|oEZNPUd8bt( zkQnNDURd3p0OkSuJ4QQCY2p0$Ko@wr#j)qgj(~ei1cW&NjLglKf4QIjU1yJosMW7~ zrSkE^SeWvxELvLG0i(!$BQrs}?-EP9#y!6~U1EIZFEjf_24V_N$3n@-{8E~Q5J@ce zB@y&Dc#J=P=UyFK_YwoR&>b-0fh*@D)qsFlZ5A845v0;aiEF*CL|&N1M>)*g`pT1Op(b{aly%Clyqv zwQybZwapVkx4=CeZEN|Ip2eik;N%2ArBG&6pGTZqwMaPJ`Bkoz0wxR{`{|d(Y!7|L z(r*59VGf>RJOmC|*2MAc9ONM<>G$z0SJy$YKzMtG)YF))roK#^n;V~`D!@C> z4JIgfz}{g*!@JSfk2M-U#ZKx(hsu=V`0jp|b5B^to|61Dn;k1Lq6qP1Waw|7wMm#F zRU%xfjBhy*a|tQ?>WW%xfKp1)EML_P&c?2QJQ2A;7IH1;t?%gMY z<_%OCOGL~>(U>Hl<#!PC=>u-p->s4C0Bpw$GnbK1E&2IFVL>}sH#a;$N*c7{9Q84Y zp!xEq-&cC8x15fLCFYy|41!Py-Vg3i2bt<0?!LHZ!X%h}ALNp-p2uwfBz9fYU-O`) z(bj)x<}4p)$R#s5v7+xIZJi#I%8~f*$bNd}kGV@WmN`P8e;R)C-ZKO{d)IBTB-tqR zmuE}2`)LXN=YP=hR?F3rXK~EK`MK<8$nO5W!|LyjXElLO4Lgg+n^gHLT+sNdeL{S_+CzAUx<6 zHzbPSD2MMSf&1eVIh#^yh##R!+G=*tfb%{Mhk%}k<$&Mo#u_4eAg9~=pb6X9RYab)RqMi1Wbf-5aPYNtg5>r)&`vulO!Lx zKQp}JVyBm+{%(UWFjV`cS@51u<0*`!P`y;cP$|-k`_XAgq{WYv3{OATdAE3*@D{ww zOUoE4A@`;*ROYZ(pAEI+m}tt6JTfR{iQ&qhN64sc4tml*#vzF-XmBCJp@4nR{phyA zUkhrAyeTsea@r5_x2h`|H1nfZ)PiX{D>R3(20tS?zNpQ)Fl zF{$ClDq@Z7r+qH7-?w@`zIoW)-HkHaHOWrlF@BcPWn+Le4XY7(gC(aU1d4ndF8D6B zqhgma&>vG+O?!?*8Mx+^ymCLb+=kq(#cczTk@jRIDYgc2pjap5fHxuU+I0zKmcTA= z9?0?zS?fGmD%@#qHCHj|(Z{Ay;1K@1EU$Vw#cT7hQ3migQ>~`!SY$1A*vUqcI%&y*%LywMb_!>R2j7!lzsZ=RZ}E)7LnxW!2ek+;VnKRjjeM() z4&n1XLXj%%-&v<^I&*NON?Al(y_G7$}(4Bps1`Q<@)_8 z^s!p*pbl8B1#Gzq;zmx-f){h8>3?hobcjn*D#uQwBM2WWQXiJP_U;)$EIAkp;OSAV z@Hr@%bu{>LW1t70AZ=~go-5_`UPxPKVRQ?C$HC|;z(q$1T8IyDt9KZ;IpS)+fx{RR zYfkkV<@f=vSKc5RhlmC&y3t0sLjQxckrH(aX>VEP{S5|9|G9n>u5pvdlquNMFW3AD zXZ`r@v<^AwqMh%XwSrDaD6FyYe;(AMs5}DIy~L;SVhW8V_)54)khX<2=jnos+UM>@v-5CsqFyz+hR>Bm#ZKtf>_`^_0VF4 zQwuh%lvn|Mdlo)Et##W6*R|*0#&k7m{=|DR654nRnO_nROL9A92o+It6!Oy@H-cl& z4Hs-?oA8QlS2(T>xIP$li@3bPJWL zCt@(o1ksq70L65(5=y=F5Y+i>nUa@|41M2%r-;9@C9i3TQ@Kixg9)1|`H_Wu9t|1g z$L&3TYiZmB_Yw04@&=WwjqsEVQEzJDkJWz%lI^ku6BSaXjG z7`MOz9kzYL+^EX(tUxXbc7KUJn=57A)lHvTDjIG}HlAELtB*BrON>5XEN&AU_#DU+ zfpByH7sf@y%cD`!cd^>4UL!Gz%cp%g{kE5@qx||1|9x311*5kgv3cK397o&2UA1RB z54t6zM)cNwlNKE1sVsQ%5&P};7?{w+!~}>Fay~vjl?lC)lm`>kEC(TxGCT@TuIFou zf7+$(g|7+=bBcy1B^T}g3mqq>x0dATsIBNFDdF(Ia|%AeVaI%4R8o=qxqqW_{C4gU zoCdONNhuV(xFR-2nZyfkzN-+_c2tZ@&mzc`(|*%JjPKT_{J-OAx^zwbX#Ye zIf1r3Sw#ORRN*x{ZPm|`i_c_Oap1o4LD)0=KffKYwF;43fNZUowKM@s)t^vn)5beiaDxLsQ~-a zF6_2rCuZ7my8$1&nA-LgWMZdLhZoV^4DwR0W)dD^_BF-=1y63vo5v6Z^*i}QC8GnI zWeOga=1%zBI&5&i_Ca4Q_$@BaPx)^U-(jMhy+;z9=oP&f;F8;d$noFvhFI{!tjY4< zR59gp{QYwn-5m^X>BHqfxkc6)QaRAFGA5B*&Wdh3z%_8*x=(g0dD~77T2=ZJ5R3lA z6+2*_gPv~xx0nnT1?5M@#Ied$szAFoV17mu^Mjt0Nvl10wTW$I~3rGHMS9kmkZUl%D=CM!va zyc}RceO1JjFFi0NA(I@piuj(byj%uvRTQs@S|2K6Z3Hk)>f6BYmuvp5)T4Z3B|~<~>VM?$$cFnDgfPoJVF(rUah2`BQEd!L zsvKyd(ieF%YxS^%5jg@XO5}*;5iMD%lAKps=l1H#|8dCnzYPMF-vLX<1I9MSdb(0I9i_fMZsq8i%&*}?8mXJpecGxk{>PJ%j znG~n2@G3V~MrlTb`&Ilr+wEBdEy;1P&nS4}z61;AW_N-VcbNb}xHnqr#-445HF*D} z7L{TbMM;E8>9{R&rqvNQ=?Zoa#uvLQuxl4EF!bFz&`PP+OWUA#MEUIp%wGfB-e61i z-_>{p5lu#69Z*C!-)S$d7le+*5BpHz+pgPyynH`}i|Fa;A;W$<5dz9n2ah07r!fU? z3FNU#p4Sk5tVz~p2=JsH7V zWXTr+bw^T&j!SA9GvL5mLN0&jupP6rv)2bXS5EAegi|B2MMr?pTpim7X5Ejh?umI2d}fw_Zs^rlzdMt1gF1pSu7*f$ zlYFew*w+_*u32LmHp&DV^&$`~4v3$}f`0X9#R5s(!cu~)OJ%O0w*HVs#oJm1uD#Ku z3Al^${5kR3VL(m1mfHkgTf-&tvNPuh1;Gxq3+P52ef=oFjxlRVA5xixTzJE>1dVvm z!#@F)E8HOXvpqGw0_y@n-i7rS#-E+`A5}(E>Fdry85}c5zYe%1Ptjb*p=77bfe=Lr zH5u)PbEj}e0R@oG&f^aB32;_cSC@cL%Dc`LNatYj!C-Sp2-I?Uab{UL0hDf&TjE>C zpl!ccHLUsDB|Q2Z*_5CxnXZ@I9n#~7`l^gmS3>oG&=IUq<06UW0lJM=ptr`s!665D z_s`B#&wx^gFhkU})6gy}60{B>IYmVr$i6+mv#q_|G@fOmu+Gd^?zb1 zVPOzxfH}w)=m0HT&BW67aZQyn(gjeG+n_V;cF@CKnry*+re#MA=lqV z>J48;>jJ>37)xUbF6)A~5FLl160V3eti};om?aHD7dbzrM`b3)q=G7VN^_ddf;sWH z%B2q5@pxyZsI=7i=n`mRnjzFgrJdwX^ZL6Cpfi@*gOG#barJ=A2E8x{NTedC4vEp2 zrg0N7T*=gOU6S-ldE`ViJZ^?|lQf{(I?%e*i}(=_0Oq-VO(urn7cWk;pnb(mK%=Zp z)$oBQDEHkpI|qad5FG+$Q3?gxRx|GBper0cAah0xmQN4Gq(=Z0sQE87Rgxq8Ieskx=&L0KkV(b9gy89cr!*$d#O{O zMJHZehY&!{TCe18KJQ*ooQw$AjM4}h(1~XHST*_v1V{jJ-sFYUxJJRDO3Y#NZD!<5 zbi>14Ek*oofWf+DK_P&iw)HY}Svc#zicX1(Rxvypu=Gm9Z8f^u)Tw>9Xv48V1au}B~RhLpS2w*PLp!arE$u#8lB$-&~rJK64pFJLvYf+)=BZc z9j@jREUHg^-h3c{^T+;vy!@@pB@P?{Hp* zjAe!D#2s0l9Keaw6xv*{VvCzB;OtGEnnZNB%rHCrSX@x zmD;B}a+$$700Vxq*r2+|o9{gHvTQ490eI)n=-Ynkf(dpkhEj3RT|)&;7^ZfcV>}K-Quu$hwZ=B@tP!AgEZc4nbZwGKC1TJ!2_ETvS)A;QyD=-0wq9Vr!APN*sR04N+%A!WU z86l8rFsgB>7(lIs>7t28ImWJ~sJVIh85lfQq3u#Xw^kZ4J+d(np?_e|8cM`c02`}_ zp>wYF=T)`By6rekSu)?uyOII?2wuueLy>TG21U#BIf8_TP_D z>kGATZHpep4r+oBq%&3lWnipR7kf_27=4E#RP14Vt#PnIll{}p;eT?4XYtaquRHLg zUwSoEP%>YCt5`mERZr2lm?=L5*Y+_FU2ck!;}ECPApms*FuCM;(CIsU5bjU)9+l!e zV&jGooMTsZve28tk}Tyq>{u1|OIas*WQ^b|zmJ4p*vrdrBzY_g;!9&$oKi!`h$m$4 z^s(lFv&zET=X~&(+Dl7i8T{QUzE{ViSJd}R@{C7CTM_H~pq)lhx|a7L$kh<+5rzJs;k9j>AZKiH#O4hdUOI)pPQLMgZK`;8Eh)I2;&%jyUD zRH2{nu-#_x+5qG84Xy!7KNMB8>9ViPKl+6EH+m~2&ROIQI7dS#q; zpY5@YP3z;k-X{$Ai&d8csfG1M(h6t?voWg9385EOVK;?7BBYI+^gat9XBdD5JESyt z@|m~&pcNMvzj605J`f~J1jU}ZiWMWgZEi-+-W?=RZMcJ~ac6&J?Hyv_e@j&f{%f1@7ji6Ws{ebEDw z0BrSCe)tfdombMJF;sTNvX+jL6afGF5{|4!kE^5ObFEbcS|1d@)B=$iRBA$%MY$N> zBqBiCGjhnt>CrE86iwOyqJ8ss6(gvI6g1I}OK|mx&2>2V$NO*s{>FIw+_johogNJhcQ1g?4vn;S<{mnrh zt+sCuR$@D-r*+`j8i%B2S1}t)0hT#&GZQ>x>&2qkr(%eOc;J+PJAeSAW821}gZuBD za|0-TkckEuUO7+hux6;@3mpX`fVqOK!x;fDs**iBmW-idWJKq)JsDY5Ri&B5&iM*9 zf)%vW0Fqgj0k9UmGGx5%EIJWNmmLf3QPMt(Kmg{qWrEBnJ}Xf`qH!$)H0YJ)(q4weqCBv}W9i z3Mb_lz@VuQ$^2U}@&qB({Z3Sb5sB2%jl|T|2G<@6i&?4pw^6A2UEHc{B8tECe*mqY zkij4Dpth@D1L^E(7l$#lhn@CEu<2#$|hi0W&-2 zK_KVSeBpEJ_U(l>BEGMw=1-%)Na)e9ZNx99TQ+F#|9m0@>y4R+z5-s2DFtxRr2@_OWhaJi zCv1*uO&%vDLeCkwaTuDfc(?KD)>!6e1Er6298yrr$n{3Rw`yB|4%nJTj)Wg;Dl8DvINyy*Ah2+WTf%UN5;HPlVHrEn>dN20PyE?wA`DjKHU=EF z`LAY0f$^L+r(ev$pk-i7$r$q7x~&?Gzb}Vd5{Ai{p%EnYqh2)k72oc;xJ{T4*B_^n zv8SLyqT${IvZ`+w6T~WNR_wNNgoOEVzwoa4y?KzKE*Ga3(mtIhM#itKn zC;AutcFhx{7W8 zXl>X)ci-(T?SE5DaFrx9(cmw*10>_X5iG|_3^{mtp8*wemHlwTpbQu&OoeW}r(}#z z;SLq|gdDAX($|MW!|_6MLX_Iq3t6S586~n-$C7)eUiSivXFXyn^`2(>SsZ@Gf1hn$ z_R9U~#iXO0iODJ*uFB}JxgW+F(t{!JflZ}Aq-YXfop5RZ5OD+nrSS$we!R(8R}ZmEPxspWhm{+=i&!fqL)v0HZ`7 z=--w*Wa!Sj9VgKdZ)~6T?I1^VV=;hajX(y-RsP)=piv+dM|m*y5)PXIJUfa@%CuGa zj3UYPCsrbVBb__>WPDb>7W4ekRA?ko=1XdRTl-9FL@TOMV*IKa@ml3!bf9 z=d86atZM2CcWU@QSttVl&VRbhnXs$Wn*z5Q}>Sp0R}F$bWgygLVTCDJwv;wBi4 zp4wDm9KDuJN@_Vj&30sfOrF;13NS(*9{JzaxAV1$;y0Cmi+=k+CpDqK;t;A1={$NA zIhd!s1jOv^@Cd=W50J8_IDppfgMLf9P`RA4NG2(R*TNY2VUabnT;3Lw@=c_V=LF(y zDZHQc9u&uK;XQnh8jwxJr37kRbo9Q(CgRRYz^TpZI2d$HN!ga^o0s`yW1#FegE+uR zg&q%NOaH8OXT1bUTGr0t>x3)^fd{wo?SmD9=1`J5i4M=8mS24>lDk!#>sX+9(J221DLj5_bWT8Zx*V1-CFJi(_afw3RRARkPwj33Q7XO@M`KG1vUv2 zqI*?BZWXI4rArbj$k|~BNXN)1#(k;Na($=(hVHQ5N|}VLK9;ZP#-m4%PKL}DUV?^P z(7Js6EAvOXkiHqg*5u03!~YXDZT%wk+u-C(rhys`)au8)?QTgL>8Q_{PC zxyl(T8?yrlYp_dPPs^PeXf+G3#GEuD zs(vQZ%g`>mmlG|)wwcHSsk#d$n?m$lfeBX(MSA78ku&#-Q+@zdv@sBUlBK7omuBaO zTwNLfaWh_qBC_doaYg%EZKAbZm(Gkfh53Ti{3$vT!0=`}{`fs0IqqF^Z_bYqG{8pE zoV)vrK^|c&vr`z+sKZ7C&oCsCDZcse!4wPk(#k;A4*CSzzDeWN5?CHvKLy}H#lB>q zllpcozloLQ>cIoOg!7>QXy`Hl5ts3(Hz(j*`YI68qFz!B2!Ft8#e<4;!>kDm{i|_0 zUjz(PM;Foaj~g=zhXM^^y*bKllJPQYXQs}VP#hkrsQ(G(Bp>$)?HNaSGodtZj= z(tK<99i~b!2n@^Im%0*;{g!};&u42_4m$X0Ef>7B)dogNqod897Gf1|lgFXnX zh6STcLjFO3ScH=qkmS46Z;O-(zd$!AgQm>uRf|%>@M%u5&w-+QmuExUX#Dx6vxf1O zYd3yY;wg9ytvDOIP?v}tOCXTgPBZM@O^>)l?c}y9nSIjJw>2X-sY5OaGM`G6TSXd2 zCEOoUX6ruAw2= zR}ICLLopo#Jh^Yru7B`lO*~n^v*@K+KiXSp>9`(P5$W=GiPU0R%wk4jzWEBr$$9(; zfABqHuV`Gsp_rb@>b4$*x3Tk)5G)Ub(-=Gn0bnJOHWiG%z$h&OsLA1(PgojhUX_Aw zu;?|j!z2hSY}BZk#ytN`%5N86b^aj>$dZ2z}WJAX_GhRvhzLcGjxM5%T_NlHtV9NKWY0&-$>u+Je)5s%fBXr@IEQj zI@al(R4u^F4jwx_Y$wIKGs^gaR`4e+s=F)>xopUb(G7rbIp|o>kjBTxwyzE5fqYQ- z#%>^c)`gzj->|x8qZCuDYG0ZSW50A*`y9VW*TsYs0FIwus89Bl z0gUCVDaXq8@1&)YKE3roXJ}&q==iJNCP7dJe#sQI!Qp*0W~4gw2}sqa!2mu!5mEcq z#oQIFq*Mk40z8ZdMt{L{vdViOilpn^sW+Z$kfJs^Rx`2gzrHmyTQiUzU5v97g%oos zn|riVZA%ay0)t&dmD#& zb6xsxL$snU46wNZ+Q}05v>(t`3IzOla=zD2S_@`*k^l$;;9@D=E*sd&XB}rY7E(A8 zVyK`sBX9P&j9on#impTu(LmMJcbH^~^hv))s8f&D>=Y}-rH{r%zqbBZBOziMb^O5E zKn*e>ovwDfNk&JAjiajGIjK^X0rcp*Cl-+0*jqZP6wllENrlz51dZm+PvJqJJpljS z78T*c9s|a8qcbxZr1n~{V6Va@zJUT#--VjFr{SaDWVeu^kMHT-zJECMw|MxOl0u$~ z&7V)-5=7i{0=V2-afY_7yHJHWF8dDvfBJmcsDwqt))R<1JTFfQF@JS#w!)`pT+f94 zI{(&uJ85VMkNuC_xO6&sGJbc1{H0CvnpggHp~#s8W5aSVY6K(rATaB}0WbtmFS~Uy z`hvN&hVz47cv6>)o<0`zf2_f9(X5Lgxqr(C=YsetyQ~p4#sqL1O~IjoI~ZISkC{6v z2QZCFy#j~d=_w0orF!4eJ2#zNbVtri9Ng(2=v+?Dqjri;HSv4^p!$nsfDJ&24cEh7#LqkJu zfE9ozF1iN>>`cjWp}pRB6hHC)^hq34g3$4=HeCJWz>qH(tPab}%#6=j zo(&8&teiH|6!5O{MEZ8n^oNo4T%4y03XZ%?wl?a2rmutf*!IgKtvqhA-Iq7IwwW(^ zU`Sz_pxm3%+1be=EIgWAc#DM;7X3%X=|tTtz%0B^1m0Qr8+|IC-4C68!xe?RzJ-cXDL{5;05Kv(BG1q#%uRJLn#78Rq zeHTioQ;hvxO1gjlu&|k$<0oD2#}2R__*WGwZ2Rc6GGovU-B#55E4%#xGS{`xj_^!8 z&TN4C7e)$99y1<|RP1tf_6|vxkW*!HI-X3Nw>zbsP944>YU5ZbglX{)}A*j~*aGJj@IU#D*k>7eVg8jg35}F{D!t6ZVw8xN)g_K~635UG8moGz&A)`F% zU4+F0&kT*t%}~kzN7#ACW8Js^|1`39_Ku8f*?V*vkwnO*6cRGCM@CKxDH0-Cnb|XB zM#+p&Rz~*B%=#UluIs+v27LE)Ih z_X&f56QAHa`=&CTF=Ey69|J>Yatq`17j&6vBik0Ha_|ieFEeDVFl^X%V++0i;uXD} z)2sNLueR8NzoGciBkl;?y9PD4GsHyven;4ph;q{Ey{-LH83-#mi!333*4cv(jO8?J zMQ%dpz#Bu%`BFutDc`W^34^j}@^YsgJ1^g}i(U=;929ePX#u-Qgd-JZOPT>S7unvD zKX&x_M5ssips8_4b;XOCpkG=WyHSIJYgXYi@?dwZW8{W zIb7#8arfEC^q8pVzN-yk4DHZ4xnkN6&VtLyc~O!6opZwL0QWKN3G64*qn6v2=h#YZ zS7P&8IhGDEK99F|muqJ&7;9hvH>Ids;CkTP>!2)-a37y0I0xz~VJW;Smk;&bYckGaCr=N8~h`00M$1)6}+utJe~xS7yGWWc$So{9{AWRNqbeBV zfk5Ch23yE(#bVHnyou&i2c8lE;oUofNu9)?j;@*S4#<_%e%&i4ycV99nV|Fb-o+%u z-Hh1W!S!3tGg;3dedsu!yd&0wYTR$(3f~Y;(cbtxtbv6Bk+NkS7frxfkM7jyTy2x; z0%q_phU(xNU~jDG;5>~R`#hN)MFgA5^a8s&|3jy{gfAMj#cdvWj6dxT8+=(*vpUq! zDO`Y$y28jB=_kDU)s2NKL#WB@*f{ZS3}}QZp!v>{^p#tbc+?O3&!76GZP0*uF|cb5U0<;a_gLDJT+eG0(^{Vt>tEX zcEN_FB{(LHd1s2Bz4dyBUasoX)>o+SlYdzwE>f=x>W*=%-|E)u(3j+Jd##NE=Ez%R zYBk4+`dSMfN;S%|$atZ7SiD<7Z6oTp>-dCTw8b?DjmBk#M#A9mu+67uT%RSL<}%3m zNYpH!?!L)Y{k-z*`}J7(N;p@C^NSP9%(`C}yYM&M9+RFLwtBe#F`Mgf4<}O{OYQ;c zX@2Hp;7#GI-FWQu0Y2h2lL~S`jtQYxVrBs++T$rY{g_KVGpJO+S zpz2Q*MeLs%*l$Gg1V=L^IF(dGF6M@y9+JqWRJxr<*GvfOcNwo4=Q?s8e;Ul| zwrzRFl*0P(P-uB(F)N-~rvJyElkssTB#x30M6YF9- z6aNQ~2^m-UPIpFLUMD=TI!MaAN9Y zl?!jKtI%bsml#>|g!+F5N$I_+jGUe*SiiCpXz8_=tf82_R%$xSD)y#%`p;X1syEnP zM+bcB_xJM`2`f#fIw{%DHEXQ1H$kDT>BA{0idR>wIm4apWAaGOaDT1{>A+!Fx|hF* zZ#y0*x9VdID`QxMJw^TvPR-VP_=p;rXiE)M_Iq=gLf{)#(XlkHik8^`QSdQY6bHdM%qwo8G zs>;)zexhcFgzwYe#TP|2*DpD8%~i5TQ4~rNP@Ka^5@Zn2I9`jC%ylx#RpU<|o@%>J zfSs<7g^ks#ks3x>*Ol+0C~t zcSgRwE;Fg2ElBy@n2a-j+?&nGLPLDXh>fmrV7{t-UdmD<>{rnD0U7g&h=m$5c&7>W zI2C-kgTahOxi{U90||n)Dpc;2iU$;9XAy^Mu^8_J#@pUSUEM#Xb>cwl)jh!Q(V&YA z=9=)ZjB>MHKj9U(lrvBct=#;6PV)oK(|6}$*wVDPjvJgKG2c!Vn^SvVdKJ^47$-IO zd*=^b(k?ac>2W@?9^`zS91vBFO_3WikAs2Z7&x>sG{5Wg`Zhrj#vG#7mTkAB!vAFO^Zh zrlw4!F3#71dCME+OKbM%?=hkbOf$SGgP*)eM3%dk8f zhUa;0KCsu+0V6lR-8o-eK1_M=J4I&1ZawpCFAr+K-~4G2R`Q=Z?#YXKsB|NV9z4Gj z_la5Nzzvzbw!`4jf!ju1+_~3^2}9JfSNGR#nb_XvbX0GiyL->5Yi5{8I5l*=)!oVd zC$ndCCNn-6bJJkn^&ip^cJ|*D!+<}B2`8qz1!RXBI0jmd~!VYLmRF`>&F~VQ=gN%hi2El1+-UWq~?>zySu&|l8v$BwY5S+4|L@{ zHkuyx5n_MY;eg}tN$hu7rqA~Td3p0%AJ$Vb^U}FiTu}}k+G)VOhc*|{ie65uC2WaI zdIyt)%)y9Fr({aN$?uUmPk!}i#&BrpG68Vui_3d)oqjMtFyXF;R zd;qO#1fXTQ5nYs5Zv&gs+ce_RX3u>YO-^g;V%7x~wkK(&&6wyuj`|2Z%5#kLu`3Zn z`sC53riOV&wO8|T2j(v=zQ&)7xUMm&QT*|A5B7c^fY$h&;psQLKDp0#$T3>ks=x;T zbt_0905k|3M~^%P3UJZ_1L`LTx}jH+nMtb&nqNeRdMSeJCNxk$z2UrN?ySmVRbs3L z<=$usxz8oG8ns<`gRaM+uEh_CJ(L23?=<8UdntR3%& ziKuRK@9rI=`lBJe!f}(e8r@7Kk!m9N0RKPR>v2`a>#)?`1D&pM*+n+~s(9Ho zros34Y4z{eR2@ENGw<~(@@GH84Tc76dGGFBrU2UD_;}5SP@IKAD~?sIE$ZTs$!6yv zew=6SN7qR>EB&m?!$U{h)0Jn^YZ~<|VSF4Y9~01_6LZ+3z=e03HgPuJM&n`i#IyY1 zy~Rvxew^M(zk-cfo(Svw=P#=9?wv806~zLE!ea^xJ1HEB19IEuEgay@wtxc~X*7w8 zi(4=By+P16Lho0~XkUXpB);sf7gw5P^87xIOuZE^>wC#F;L^Efa)IVtVP2dqzW)~< zEX@a!P+$V{c+X+gef&q{_^3fMNAK;1(2;)QV{^8`mhr^x=KUuG>lG22=fIK^dt+|q z>rhWfD4g9}N#_|~;_afDq_o7^iRr4mJHaW7?9_Abzq)&MHLv41aZgRZkmtdRvj=o| z>{wA)1Q$Th5Oz2@8vB{?uKLz1J-wGw*ChuoL`7vyZu_Fj?j;%=j45_Ke~R)yk#YI6 z7<1`l?^y3>C&Nm=34A&`-(S{$tQd;xhe+jD!O7p2au1I(DJTjCY^lI1+dZQ&&PA%1Zq1s!E9w z(M6*Zi$_W)7ra>eXf%}E-Ga+|-0;{q)ln%@?{T4kcYTdOv4RmR)*_{4DzvU%OgE~< ziEh`;|9H2z!?nrYVU7U>t@ZT}4PzITHim9AZ7=F?U}@se@;vEHUUu?cIy+yu^$DkS zqe%dd4b9T5OR7gFRijJboaiZQdHjo4OE))p;tn+}_VpaiQ~Y32n_!81!GLFpFh~;c zK7OAWQ+&TMooC>Wi|w8E5erts~%JzW#V6{O>X+9AYOs%KUQ^g!2H7-EL@tx`?=0R|k_O*@ zTyrX$4owhz8|7JIY%XT&^Hd=<{p#D_E0MpqvM9|^(u?QsURDcRPKzPGF)Q~XE1He! z;oZzkg&%kvN>XXlAyIi}}edT@^SkNpwNp zcbL#wB?Uc~FK!vKgS%c$|1g6 zc>)2Of?xeqi+&Ye(6a*(>XLd$1)sTm^XTS@t%cri{GKG7k>wxpFR-O1$If$JNk5q0 zQ|&OT@m3WWzJI-%jxxjb$uF})jz){gmYu1r=fR0q4*~;@cLqG)KE($i%1gxG(!lM+Ea=qeqHD;{lJqNb}Z@rlM94M0JeGUK`8 zpMvVd%!>T*C&tAe$l5xzt3Mo)8P^SJ2yWN&JwF3~iG_j|>#GhfYBW%PqGQ92IHMO% zD@t*PxbOYOpYS*<;+gMZmWf5iwyQ@RpgiP%LldN6jUQzWMGwFH3Z>?7P)gJt2QIVA za#8gyILCLh!j?$b1`cBg+KAP6;T%G4y>Q`zF=G?U*^D)Hw!#O6$5qB^0+RzRnzoLG z6=N-HYwuH2ByhegInCMI7n=I-cG`z6B)|I&IyR6tO50_{6ZRO~Z%t;o)6K?9Fo3se zcK^)DfkuAu*Y;KEYtfu)138E1KAod)871e4btP0rNXr7I6$AkB)*&+oe-+??BY-5m zy)t?huympT7<~kEH3ZQOJF-oa%*b5#*%aQOA4Yhk*>i?;RwU*w4?TX^^@4~0dVlZR;rLv5Uo$#!W{4CU= zVj{k6Tjib08#Pj*&Dd^`7fg7mu48~QV>ek`{&Oiq!1z0&5mTfG^o%MGGo7x|bg#HJ zpf9ni0p;oQ!J0vK5{kVdU9*1kJ6 z2ap}Eiv7jIo5KTN2q_P$OUpdFncVrP9V1h|6(Ir56Fp3TU{ifp84z z@(&JO&YMRRWC&pl~8&R9=b$s~N1%n{7s?e-q& ze!X7UGZsQ>q7Nporo2TEAeg#qnMw~vH-zk%&)RL#+mS*)D|2kOaVrR#W>4YDNtZhQSUTsUV`75X2;~|0HFa zKPT|(fwt!BRk>~{L2iy%1f0=O98bEesmBr{`3n}F!(FVPW3F*lX$r_jFd`S`EAIHI zx_C^oHjdMO)AWAzQ{MFOMG24w?=sz_7$_O@LBj~KJO<3ke4_!buy1YqpG^I!S>?% z^Al_R8pk%Yv$0CAv|I4VaGh(Ki{3gtBW-zN3$8K=LGCJ6c($twJA;yY4-mBx1UE#O z7VRR+mBT-6_<;FJ*4dx8mMAomk|l4Az}cm))0M|Ec+XHHevzK!rBaY03Em~Ylx5l! zownU${rNnN5~5JwosG}S6rK{G6VQC};swi{`JomAJEz0TiIzmSZ);YAE0I6<2 zNWpYQzvk$q(6hI#%Ir&{;A83h(7je*vAnt8Dgat;I&=0R(z^Xy)oEn`RuTfyI3k(& z;ZkM~f-&-$?Wo&8Z$e56lq@XKSU7mrpys8Qdmw=Hzd@;mFvL@iBvx6WM^|#vQ`s*^ zRwI+Lxj&=dfrCo(yZX6&oo812(^ba4-Maf6Zj4Fad+rzq4}M~kyi(V2=dqYY)qr@i z#! zkbwinZ8^3|D35PrVcs7q!=?W9CC>SVf##vg5&GM?`P|i#z`t@M@6&6!jDGme>%^cr z>|n(S2?+)cH@(DXKho`IsnO*Md|33Km+|6mNDwL`OEaCNHx@86Yk-%A@C4y--DEG` zVlSQnEgNKrD(sDgPEA?Y17I3a3dGyXQTkxcaTB;w4lpjR)H8Nm43q4BO^z#NL>RbZ z*kr$Lo+(=sc8OZ;_WWg*NRbA{hFd1>FLM=O%HEb*z(V<)u>~0BnBVmFBAn%5@qKT2 zzx8$e4Jqk?b+Uy#4NT0TX=ME;F4QO}AT0wA?rg7(Ga;fmh^>eKCuxnN$c=&_dPRR} zXg``bj@QvZu0|VloT5Ig0I!yJ3f7J%xARyvEkZFk>QY;$IQkM>X7>}EQ?B&9I!qG@ zQgm6ZZ2H-{>iZoep$6Zy4wVM}JW|e{mUYh9Ewds=VBTi9SPP?HwFS3?4lL<F5>2Td{B%G*u_Cz{B!Y;Mo)tz?hN~TvP$7D3-)Ki3M@UK zgI52>%qsbPMjQUjAI?6CcQE%>c5!Y*GOBp6Tyk9 zSAtvYY_1bY2oxL$yZ{FO0)&Byo*9_VfW?40G4|COR^GXT`G;N;SOU&MbaKr-q57x{ z{mnX+Sz=Iy1_mlZb?keo zy0s-Zg3Wojwwy^S{oWup-Y&Sr^faIo-(T)}IyjNZ{ny{A2k9X=tUhQyN$7hA4@H0H zx(FNs<_m>5sI1+Uhpf$Grz*2fLRgrqZ!bAH9m=tCKPPN%9$UCf-3ffEyl9r)qcY!k zLkR#)gY8P>b|(dB<7yPG%P%u{tT6S7iDfg;N*NBBx)f%yA{?ez_9CI#RBcD^oBt1{F6_ZeOtvu_b5e&_+=US+u$*DKKEHlsd_jI|%Uh5;d zyi+a2*+1NWp`LSB9?s2nq49QaX@um8{rR}eeApsefvcU3t)-O}{qxM3rmwnwRS%U; z2ntQP#;;z*TdOZ0e_H}-a3>PwTbvaDf!MOfiOl7KL1$n<4HbD};LRibalksg2<{(tB^P#BF`bv-=?K=(6}_GSS$t_|JL+cn z<#56Xa(w5yPYoF%l$1^QY$&TBQjqONSU#|tA<--`3b%9}OH?0ZaHtGExjc{_R$4J} z91`ZHt0ZWsfuA+_9iQAc$8~3?Nnua=L*SZ>^4oiRcgg5p-po(5y;gG+)#)Y9GvWHp z#O@~&lYm&k$KQL+B-qMg?_T``64AfuH;@*w8wgwGWn7gd7snqrqPHA~wF(3)|}3RnWSlDNg#-C${L1xJYg5G}_R&K3%^@n=7hJorG6{y0f2 zJKJE_b9B9t*nf}3<>Y{1^LBrW`r+-=%)zuT!D_RFICn;8cOQtKHS(5*n?_$x5A{-x zZlqG%^uZ{DZ-d9g)e>@Zf)H_cEp%h^`2+Oqtzdt=wvkWK3tnUAy2G~ZnN0*PV7(Af z(Q*<558=?8mbZd3FYiAXTeAai>ntJcVfyg3EyAyI<<$IQ1e4cdRX;(Y#qz^%o>xQL zAJtH%hsh@ex`F`A7HtG9fX|M zS{ssx0q0pP<>yzVRcB1QK)f)O>NTO_>syzY0xpRReZmF1r?SAT*7!(su^O{rJ`QR->Z?k@&sm|kx7%V1EKL36zfwfRxhiaUmVVIfAA6Bk z6}r#j2*57Gzu+DnR>1@}dyV1N6?I>swPpkL(>lEW8O|)t`gcbrEo^ z%QLnowiI!8=Xqr1m|-7q`@A2o+!IUkC(MgU?w^?XAH>||=5b+>isQ*XFDo~X|0I<_ zSvEhH0Q1Dr>*hcenBKwGkGfT93MnEt5EKbKw}Pej&of~WQXjA?;T#Q0z*eBABC0@6 zIk_LAVyfteIunt5_NZwt{NJf8k&Th?_T?|MPaR!h5l=Rg86Ykzf9T$Orbm$pj3s1t z?;T?NV}Br~dBwT1t3TnnS|PH)W%N$sPe@sC7Tre$Z)~_AMV~})I3h+iV1zUyljh_C zKd~|yjkh%$CUI2i8MZPJfV|}SWK`xC_PRm?V&wwO^UvL`)H*}V=7UQwLDboWGvV{L z^^8`EO?jkrpEM2?Tb`P6tWk9v6&%TN*%3M^C{B=cm}=b;u*jjBK*h1#|A;cq?N6Er z&h$Fjr;FA=Dd;TUZg!y0$aeSzU#YRvEvDXubg2mx>=4Bn^LjeY>T0%M!Ln{60PzpF z{s5EALep0Z(-`6|MA}ZFc%-UYT2ViE7KV%2z?t*}{_w|4G$+R$#0O5p9Zm3yX7IvT za@DAq^Lb$FB=j~iTcDB6GVXWbKr5EZQDZ&;Tvv-;H@tJ~?E zh3~Nuj`Q@<>Y$V<8Rub;c43cUQ(7xkr;OWLIaCHFCU3Fx#zHM5I)H5*dUA3BLf2Di z4zhPp!Ht`;xdvm8)o1S>-)8Eclkk%Ncnj;@dorXjw`~uq-@ACTO;}UybPp+d*DlTA zd2rmR74R+0%~eL@^F4nQ5s_I|Hh^qm=5}=YZvJQlYa&T2=34KabWz4=B!msv-((>C z&U62ih~aWSpozP&t>g0Tn~eTKI0{{GX6?h|?|CN`R^mje3!ed%b*of4+X2!8612`d zZlC`95r9(eW7GEa5*QGDtX_N1+bx$!VNDKD)6M#EC17p zL!q?h0+!82WMZRv^wK()$&V!B@llYK@x3daM%3|_yCe_WmW@?|HL-NIdIU|%Z~-f% zmm!Fr)$r|*k^8N2T+`}mP<75|0uBSr(Wc7!jv_JC-+mgqvJ@IoI(S+?7$c{XEoNY@ zVAofF&Om`^=3+5*FRnE(#=RM!Z`ZqjyJ3^U&n1go{~Y(L+M~$&_C}I|W)6-Iu6XAt zYQH3Z6oZ>A1a7kOQQ4zjhe|$Vk=6EX*J9G`$`{BLJ)E?wpSa~NkiEdb^d*}bZ8^x( z)5X*ufNsn(Xsk`c_(vd65VeNeEM!6EkM0QMMKo|H*B7B@eJt*9{<#V6$-lN{T*UpY z*K2I|_T(jg;>|@5*{rv3FTGtJV+%SMD6uSso3uW!8UT4gI8u`3}#rCmR&Iptf3sgg9i@txEp8g83KC(8wHzD;!a%g2;!tFfNCLt4O%XB zd>OaXLrCE8NvXko+gm5$u%c!w5H-^qe;G1tnUsX_=e(RoSRfsY{gi|I9s3p?44_<{NA#zRoAJVjCA~cq zard`L`WT+tM4P9!lNV@HVzXwSVVAa5iTb>(cfa()SVmQ?qjK!fg%K(aY`7e8On}2kcc?e@zD4)~0u`W5 zdQ*g6cH94eN&pAe5dR+5;E}c_&33;h41kIG%anKyj50;lr3EJKCHAOP?e=>j^nigL zT|}MNP%{OF)HX@XeIwUIf4~xQr28AujUwm1%)h z0_B3cCX5M9$Q1<|7GPBxDaWtV^vh)wenvo9IIS_baTlp9sIKE)MYSLo<00~>_B)() zAuMEx)b((H%OW_K;1BA2GMo$oEW_x(qiT!%?~4PBm)hK|nIjDS`7zN~c1_Oi^YmRu zet2y=$;~jb|9weI((&9WjNL#W`v|wvR7>$EElf9FA^~z5jAij)yt_m&Ug?U)K{1 ze91U{s-xT2G6VtniZ~VNkSp;6mL%Aviwt|!|8f1FWd4ED@I(^9PyuEB4X+wf^q|bv z7wRP^eZ*2K9eDcrF$g%hD2~wo!cvJ|ACWmWB9-TqnyIDp{?P(I$Qf<75XwOYizH+tIlauZ%+iMqiqqIg6pB7=bXg#_1f#ZigMQd((z7ibP>&NhuQF_kRw?7i^HaOA5-Ud$n}?V~~cFMtj?6tc)_{Eyc0 zK%rN0`7ieIMWQfA_Js!FLcuLbF1Tu)_dVW!m;z%W1@4>nAg~%c?D`;lKHyPNLeeU1 zvXB^F;PWNiXVRU;r;-<$&ihZK%KEN5td=l!qFl~D@3i7gO@1%9d(YrD%xc!OLR?#P z<5e8J$iWPX1l)U|zm=?A&x}=UL2|nQLxA+eP#aKM`}xYfrx`5sF-c-}zSX7Zz&4i_ z%>0z%IYl1}XJwu(B`uyDd!2w#pu{fU zKST$kn!w#;g+#5^0Jlg4VmhG%jf2S0x+UQS#I*#IT9P z7#&#fL$KMQSh#T?8;XE65M{#xg5PZjQ>z|-z!dfP@g{%-c}G+^CZF{NQ}36wHhUza zPc({XnF-GwIh}>|9(_^(Fh!(`l;-n`0ST(y2OlBm!NylyA!Qc}btO%{_LI%^oGVzU zLWu6Xw|ag{YDhyg+=gMawB`^b7Z8}y3979|LV^7Ndl>ayB*B!P{&r5mZIGScrY_o0vs zXIp{VDHaG3nk6BE=Q7TEzGpz#A2T3iYX>+#B%`@(OsODIMsTx3!elc@-`3sy5qckz zmiejnFTd~HlF&*yfP!{POarbHw<#v)=@DbdhX2e;MCLkeDVUrIGFGl7b{c1w7T#%kr^~3oR3{3`y;qs;fxfz4uWr+mbT0uHDsoFo`R~&0}rfmN7}F@F^vw!dyG+4B22*8ms+9l5cJp8r}p_jLsV9_>d$>J#geBAp4+TN{Bc^vN~Pi=^)vY8d8N{b-6<{^WSLH{DOBa5W(XLCqpb0(y5D&kDr39 z9UB^tr3cfQ6%@G2)B$IMONeCSg0wLM)38GavKlPEl$05cdm;b4Dv@$VW~M9ByoUnG zK6KUejEwMr*a`S_gq4Csm?p14gb@-1U0Pb|y_ENM12Vv1-3D4D5dvdD;?&Me5XO}O zs-!LK9sq8po=Z#?VyVtfW;K`$oO}WA^&E(>%5)GA+tq3!Ww@g@fm7(UP>UFRL0PFV z#*xv4I6gmws3F1f&xYZ188MeJZaKApOY2CV_)N8U9`n#eq@~pE@sF#S|R)PTLT)@cCv9fZXBbiz z+)E^|0a-GYDRZBlmvj*aBp_kP)Cj(Qx{Kgb0R2jYsuBFNkS$U8?bxIrr}X`}6zGi1 zWmdbRj}Vfv!{b}4*5m9Prya-(qO+-(S;+3kcq6!UB7&1L^1tiuUu?FBUqt4+W{jQX||!hb!+7q`lOo+b>W5x>h7z6 zNWx)u%`RuMIHhTx=NQ?-%%qb4aR`iJXP^k&^s``atVnd&Om9M(sSAPf{$(b=Sa?R* zbxam9>ZlHG<1e=E1s%0nUlDAZl{Us8kQ@W|vu!u$)(zx4X*JJhOY~8s5q?ZTbta~S z)nS2Y?=B4=O>n$xUkEP+a{M6sz59%Kn1KQ~76)P~6wF;0i9a)0mmf6J5=f<=J%fjw zWo|-30+MPlVdB=@eo*7~+tVFu^JFk#U%!g|&SJ}&hZISE)7`>acSw#Rn)7Wil= znBMIy)JAsxu5W;ir%<>yK*kOPk*7m4C#WB0Y~jVG{ZK5RVxz>ZG==g2Jao1zji^f= z(0>sPCm7iNazBCbbOJ&>O3x_&yYc;@hsya^Xn|LtV;PD$N|Z-!dh%HU^?W!Tf-iCn z;6(h-=e|yr`6{J#d>sGQf8lzxu{VhHX1y)ci@@_yKUoj2qlig2!An(IjV2S!5=en+K%f%Pcp$xRtoJ1sVd?i#p zC%T>tGm@E7oFV)B*$}E@qN$%-cXb?)#Dj15DjFK=krxbkRVo9;14!|+lgM%It-SoVb>veDpat;strZWmNL;d)#B!zh3KCifzstgC!yU+pqHy_U*& zQ=!Hpn)ljywCvZ(KW+?054+OOBs#&>Ltg)G+SP`;rBS>NU(#D)7x_?4@o=gO)s}|K z3E(Zw8AWQ2EnQ?}e4WjVK5({eanQMGqTm><-9ah}e~f)OBoXGzkKnQ}KPR|1{Y>ZI zo1q&@Bhh3LpKhxf8PQ(hzFr>djw7o#rDc##fAeOod*9!=?(eN3et^l8V~GKCF$u#( zT)^mcE2dffdZl)G*3>y8I0G%J3U@3KQee#eO7)!~xT4*-1-3^Iwb%;Py)|tFDcHJ$ zYjURM($64KMKG{vY4Sl4$%i-HLseKMf{Zt9OuS+>R|2Vh$w>W)?^c5y@~xi!{Z`?Y z-_NwVW<;J+@vW8XHRzVk+pJ6@Z?VYwQWT^TCz?n}Vm{k}CS-Z~97@_OFz(n77kKg_VFU z6dawh)z4^}T}HK?0O7~fUSb6>ta5=`k)51W3Kf*&#?vI0HA(TjA_o^yd2p09x#zT1 z_n%||C=&JDZj>=vA%QTii!jNc8%dC5k$1yB-Wf&dNxG$U^idM~>Ayi6pf9+$MUO*~ z(KP=9g*KAnjT$D&P)1IvTbQ;79@3B=1d(v*!^)eC#AuNNNOce`5+hUhu_+w(8rUh?x1z3Q{c?VcU~>yqy~%;X z6M>OO*q=U6>RVmwvyQPk`)`%cNFpDfcD+paiyZLi3Kr;BM9}yu6bLQTqh+Ptd z!|B*0CNQ^Ywq_hbFDF{R#=??k3&v#p1@6+|N zM^XApqVjS}n+9tNyC}LzArAyWIQkf{nea{2WAEWm!1Cv*@Gj3=fho8KDj-NZ^Pl_} zK6!K~xUEoA){V98SB!be@cCi>%wT%03)62U{hJ6Jic!36G@Qx)33QnO*dHp`;W z&e>th`yUqY)3h`)RA-l$(9jYxJ6b$~HKwXm@>*lWW6HX$sX2&I_?vbi|1Rj67-}@A zu&R4zPDM)z2Zr6dwnp--&$rbe6Rh-ioq@{ye;@1|ERVWti#LltjFE|Dcskh1@5I4z zr*qHF+l}E{>8(Zczv(A~|4aC(fz>K(DT}N*&<0X_oM!|g;e8;LOA9U4ta-7UhDids zxpBMEJ5h5dGU^Q`Q3y*EYZLghPQ7+Sb@?f-2Z~%TImZrm0dQe=CnL1!z!OtOdTE+o-!jOGuQ-Q zoMA6T?$3V$oAmu;LL*CHd_nOIl3kEF)3K&HXA0a~o&}QHC&iM4k znS!K0rsLo3j)jRyXU}uVbd50kzUM528A2KqxE%s&H%%J4D$_Gp{FI>@689?+gN=}r zx00WHWQd0I!&qid0Q)~RNNMwH5lbKIfJbw#F!<`A+9*DqBZsxX;+P@@mg8p60%t*v(Qr0==of-?fCRcl^w5nGP2a+%X(|ezVyzhrRTydCFaw&Kn*o zd~FZ_r^!%=_S@+v0}$@NzcmCwjhuh9B~)S(2W`HlX)z06x6I&UJ&htKTlj<>hPFsm zFhZ2|8{I3$<(lKAVU5k5Nz-{78=H80D$0YG{LevskeyCb>i&8XW4Pu@ar_{GEo#{cHmx+TZ zDt&tTlTg;1H&~Dkjz-S+N~iu;UWzo^%)cux?f}VM34{%Xg@sK)oaV+zZJr-EsHS&* z;NSYXrZs}5d`m(WA*5O4QH}wkWjg^mokt=4%`|z`Pxz{uZlMOk2O+W^^7T5PG!bi; z=7WboChL8EyR?!@DHjY?1%%i_J|QSHEt@jb9$zyTpmCxXy%mOUrZavSvn z;Rq;3BcdyKy(2g=z7(~2L_R?X@sSc2B7HlY4jdoJ!OH)Yzl-}2NLXQ0OZ}stsEShoBhAR-m{kgJwU-IcE8$-&}gmS zv}5&QgRgg)3FLi`H4jCb`>j@%m=+<$icKK+s}y_1pcO!C1GqaD-|dBmH2g+LN;pwf zJcP7!SUe>H9Rh%@BI>clkWOBuUuCdc>}4_TX43?19ZC)&`Bzwrw$8v;F^A?ig&HNq zb;Qp=@zHC-2Oq@bhWS2_R@pwf_i)e*T}@171bwAz+^bg1eb;-jbI@2Z5T&{eGPMi< z{($D)Wz5bh#PeV-k$>bOjGiU^J6&&gne&|HG~Whvyz0o_9jtac|2JuB{2EyAXobud z+^is*Jk4)SCfpQMMC0vK6FsQgfW53vE8lzR-s#M6&LHB;CqWk*MW>uXdH`cAUOf{iMP>{&4q z{3KkUaXI@8N(2Z=xiwgj0Ej#uf!|;-1W#BM7(<$fWe=|Yw?-|FWR?=qk7-nq&$=uh zDnDTHP*fD>8oUP!_2f;Kr_O80Edpif1ZO-?G2aGO0N!g!g<_~VCNXKAxjU%Y*P#%) zcQ6NJ$J39e3w@&iluiuI%`!-J)#PA?;91|7Qf~csA z%&M!rk3fg%3R-K9ix;VoIC8i}5RDUgE9Wn)l)S3@Ui}ErZDKZSU7rak=k*8!1UnMNq+!2+8b*$+S8qXuV<2y3`oZUF0$$ z0P7IFg=^cL91dqy2p8{hJ%yS05sYaYnAwob9bi*!KtxPNV0W&%td(c9oIh zS51TH`;1W=$<;iMF;+3@v1Mc&5$vO~8dk(OA-LOlYb5@{brcG)kE zWz+5f7pxe@4GqlCbz?r(S{h0B`3Y@ znCW#~TwllMj|LbQ&ie863aVRCOeHUe(o+se9|t^M{fTTKWiZ6MR|h%!^w{_!gz7mzVhj33izl>sYCtz3F?}P;nJySvUHa_B zK}^eI@xssvaFj?C4XAg`IU34)WdCjz5aHzNk7~KKVz_&*>nempy03WvmmPx{#N1JT zdU6=^0|%cB4H1*9f%`Xs_{j__rm~?S4I+mIBGPI#i(wy@GMI-TVhfoBuPPmTmh3mRsrGl_44w76G8y{e-6*Xo%0!-hc1(M0$`4%Jb;NLBiDmd)&}M<>6s^DrV2T= z)%yUVp89Bsodf1Na(4aP7`RDrt z-%VZW&MN2ezv0R2A5NV&#Wdg>_`HS80yq>wu-VSd1HFT}+b1qixeLQd@STS{%ucxs z06M`tg1kH;`G4XY_3IemH?xABs|i!#0T@g?asWeq{E>qU@^gS>ARs?m3~;7EerCm> z(t!MQ+QG&ac}!d{a@>C1)zhP{u8s%Codjnha$-Rjcj(L#@yCxL#M8k-?F8`rK_lX@mSoW}o~-;0Qm6_N4v!u`wRIVjBwW^H18* zRQr{i?d|PCr#y2TVn5mT-Sd_ct?>Jm-7o)n`T19WLY?%2N(7haxc~VwZa;hZ?|0BVLNAAM=Lx%Z zYW3zCQ2N_2{ZCcjTs!Tm5=k2v(BJvsh(B}dbuQZo*$)1Xj1y}!`pM_(htE4IJh{&5 ze^Y0KukGjJ;@uUIzu&FL3)rpQu=G)TRws@7`0pR(pPwUNlE=xg<4e#Ac>5Ye-KyNr z8D#!moQx&Ha~sh5#YV}?%Uj>!>aHdJ&l?nBhR9Cj2d@?PpKD9=j+~41C>ggea?RW<`fRORlv7pln%eIKilyXg7ovKh`ChTcP-h16IS^_syJJ_uH zb99)*?fX!Qii*&=l!Z^fLtW{UuWd$f4#4xGh(9G&)-&YsV`4^0M}nZBAXswoAQL_@ zEmMk3e>;)~TFY!`nvJ zeH;DtOWVOg1QoQbskDsrmv46gd=cTyjr&U~y1IlEZgQaGv+&`rRGK5Y7JLC`K7am9 zM{~hZr*MDtl>CoX3l8 zDNfA!x~hD9Lfp&-OR<Vy1g~dUB>4CA3Z4hzkW@$!23?)ARMK z1PW0lVGHB}&YWST#(Khp+wLz*rAZ^-Do2I?`1JG=ls>~@gv?$#DKuu9tw---c7L|~ zav%34A)2DpVk{+@PDh3kY&u-OhCFtkc_arnRosYElAeCi42_9oAU0VpKRBF?44u6e0-=ynn{C&mGuH_gU=M?*jv^AnuoB3Yn#ek9~~Rx zLVGC6j-ON&AYAPk7?83qbTu3H$HW(%d%BU@@ESbP0!CEmY!K1dy6S|WztUD8`}8u4?i;weW>O*x zmkOB1%D=taG7=phzd>NDhipxhupCNQZ_-=NnY!-_jQ)*@lY4|6tywZUlV=Tzi|jjU zBUa%zVC8pn=dXRI$b`!L0xHo*LNCXzl!fwwX7KLVenk=PVi*c?`0nmF4MSiNCmCDU zn19%a#Nd-CLUy(7Cz6gecb$q+J$y>o|yTFl1Q z7}ti~OjQgvr)NFr%_;v|g_?rKB6pj~>1p#g$*Zs4<=Cr}+%+`Wn^@e_QjT28^i0TE zmGQw5r!BXrs0KJfOh4d;c4iTJ)4~iSpNDgaN5{mRg|l_QP{GNetenx&9xeTYN*1(2 zo!ZNSOcc`a*~WJh5~A`CH&oTtEddP4IapvC|MjaAV^eFhYtvl=4T|02gh2`n z<>cfNa#WBIic@kIAPwSJ-aR}iA<-op3Z{NM{fS`<>f$0I)We4lRoV|O%k(cVefI40 zz<}k*=`%Q2Sg6vXn`@(!H)N8~i|Sl1G7ywj|mP8KG?#rX>u-Mir*^9rWK@mVcA3my(!BQJ=qjN%kqp z&p#0|mAM(+v#J4;(Wlzpoo#VX%KrQErJkjgl_MTw39E~)>v*8WAG_hFZ)HPx-S^#u z#p^*uf!5QLBczfj{$K$Mt?)UrETrG;0IVwD)YUDzdqj0?Ai<`YVJe1}1ky57;xkNY zF-Vm6^V!5Q?8;5(nCcRJC_rN@F)}i`v;EYvq@*O}z*%L~Ero5cDN4kZ0!Guz%ga-| zu1ZRm<@*WENn=u?21b-dqQB#mM{0TJkPN07!7o+U$8YcX_HC`pr?eEcg6d{ocGl44 z!k3|SLB>X4%u3VnbokKuCHxyv#KXLCGA_cGL#Hskm9Cdde!vI5p?Yx)L zXc-i>JC&Q%{s57;G@C!Py?}wGB+Q%n^RpJ+DiJHvs`1A{gz(I;i~ykvAxW-_ZZ-5H zk3BA*TZ&N;$|w3F+U)x>{yH#^Un7$u&{U;(S6x+gjeBRozQbp)JD&~-387>f`0Bo4 z&M4ebZQ{=JK#`LIwT_n~KJgjNKn8#lm1ij_63@VoL800z`^HuaMZfZ_)hfw3O8Hx8 zxYdnz&%#mTf<;51&LpVfegDLrKEsPA!E7yp5JM=oQ|0sLTH`A>gj`E7qU5~?j3WmL z9_=bU?KSpAM^eNrdT7Gs%Zm$7&dewU&M_<)Q3WtvmKZ&WfrRLy@edfQ<_87vz`N3f zl@@UL#Nsv+cui5EZovn-Ipg*fS*w4VfAV4b29oYP!qYX|j%&|-t{k_Rs#fjl>VkU* zDJY!se!%~Ahx?dBh~`;zYKx(q1%{^vO&CK(UWZaL|IENPV^qt--=!X{nJXSVcp%}v zd5?sSjp`r_0qF!l?*TVAHzz!^)q_5RizlB1AW!Ll$to+#7Fib^Wux@;^ymhXTJYwn zOS|6aHS!%VUISH7Rw}!F_Ij)|@5K^Uw?3E?pwv4%PVJKrC#VEOVR@Bxmf=GGmWNTSU3JdSpm~{LmzMinXyQ(0 zn037;LQhbCOx$-**Z+f%iKLm$H4`ab90;ug2gE>E5#nx0{OHvcYu0d3%3fcBYYIRC zvrm}TR8}(Kkm~?1W(sf^d`q?h+_+ujn5 zw|96)-rd`^JiB`VP&!42!*YCmP1+aS%-YLc&-7Z?p&n}iHHq+KOWO6=!Xu5E?eZJW z;S2}X=BfXk)EfSUu4ak~yC9(9>6tqnH{|kdWEC&3sUK@$$)KEBM$z)}_0rN@7CCm= z<7%&rzMRl-HOwqBmf|IJ9q@sAP+3>6k`CMwceZt5=6DYcr3gdgh{-NyS>#-tot40ZCsaa6s1yO-jGQM3Lt6*Su`9QsL$M?xpzT_~I0 zh<+;{`DjWT-9gouL{g1TG;O%eg1`55I`td*;H_3DDJe12G4nOY@`+~>Le`5%K0e8# zM8G~dR%}q%i)JRCn3xz4bhKw6#qiem`ROI!Uwz#uBeR?0gyN+D!ysP8EItlXO)SBt z*#SYZojUc$mFGAjg}R0Ye*AJC0Dk_WqM|R*cqe0MIbo6nCKQ+&<*?~ycjOFRzjn;uL^Y68s8RL;Y89he&bmJFap5FvS_c#s!iEmu1% zd9!OjK8kvr8Jm-n)1y=qtlzlqZVij}R=8$w?*g*Pk96cFVZV#X%NxTx8aFiF=7(DZ zt-}KWI$oF%0%Vm{R4&r#6w&KKP1+%Pw!HhdpYF~%SVhJ&v$Z0-Q)y7;SV!P#RackY z7S|R%!1QoT5HekT-e9q)jBw(Af+z_=yI@1S^k2iNfA4XUH~61W+2MbOiSkU~*6?-S zk(q?U|K|^S zsnygr?f&;WrgPv8#lgX1rH{NzJX_Bov?!GekLTJS85zk+5&9TAg%VmPkN1rJ`P05_ zp;+?t>zWQGPOg}qw|BPjK)P;8{he(KsKv{ch2Fa-PH8MYd*uo@DJg_^7TkXF#r5?T zvSJS_Dm3)#m0*)9nwxn*DL?V-!O3ARsJAdT51pL!rRMioQw}&56dl04w^lgl!3kAu zZ3Y{OK$jFa*YN>OSA6;;DEDlX87h~Gefu&@eNjq?XwqZMtMx`1b0IJkXr6mQ;|FurH0Um*MJ<^!W+B==o9XPWT zzIi9e;l{+B3lM%B9Q|CWw|8%A+$n@46dji;b$xd>Pn91JWzJ~Sl$Kn%sY_;n1Q$`(~od@0}?i}dI6DN*_mp4Udx7m+setT_P zBEc^&UT8;7lU8ZiRYdNNK)j)y9AaYk4q_uXC0)64g+!RKcK-VN(FGKWCgF_vlP6Es z(3uvN#o6`*AFTyIDT0WdDxjeq)ZGtx{ zkpYB7q@-Sce#OfbvuP8#6AdW-6Yhy?ugaI39$++rYhG4lDEdJxkC*VLY zW1l#7J@XSdyuQSH@El3ZfOQeLPy=irdi9m(uPAY4_^d)Qxfkc^NpHs&-;P>Y1zN7mI?%pD*)%GlIQ;2ASc*lKI1g@eT6`g-h#XVXJjo?c!VCP(p`2zwI4y4%n&)OKTz=di`r zty{?ihulZg-2)#n9Mg5KRekej9!Ez<;|x-_RDYMyZcXL?u+8&m%4-X7U33&C9A; ztR8ZyT9~=fYSgt*NZ4t<8$-gTe*&-C79ZDfV{Urnyk{0!K8DOg%x4FFTR3!Z;|?02+<~?LDqw)Cy;#x3Ll$JezzngWl-_5$AY~bSfg8b%4b|Ai8jLk}Aio!B}D(h-SKBe5NYTzV0t7 zL4Q?2w3VD3$=tYF*)uUE4-+Z{Egsrds{b8Z4tUH0mS`d6d-}9EMx5h1Yf(;38ytti zRW0Z#rqTDp+D`9@yRo8U?&%lYbj>oY^QPocR&{sVp9zye%!DeTw&JdIKR-W5AX&?& zC*8AS@t5_%oL6eKwVhna&&Rw%H};*HkyAco3Ot6wGgC?)9~bZ1RjbmTL3)yVkzja% zvTcWJ3?8mQ9L+YcU3O{(0z&A+J$)wS>Az9x&apmZA4XI()*DD7BUtN zQ-$PTms|+{wO7(tE$$!9$q{_268i&R|J6g{J%qXZe|NS2pFT*bW*PlW8022}?c)Nq zbmY4+xx-(t!Ic^s8sLXhR=LwG5YX55|H)R9CO_*EfrkJu)W$O#_|JHQ=BkFKZDXz$R%BPoo> z<1~f^YZ zQz9*dZLxl6`f6mpUS1jP*tPZl7DUOuhIx+^WZqX=QKoStbS7X9*A;G{i^qTQ;ze&e zHB|ItOFw9Q26BoF5b&|%Z)_&!|E57G_IF#x-ICu668p}aoudye_%YEJ#`tv{^47c?U-%X9yr#Ik4+O1K4qrD5>dRD6bl z0fE1uLrLLexJs|uvB0Adf>cbgRq^q)<_|2HP;3IGQv}csp*H6CXdXYVK>R-rSTDle znq{qDVcfJbOb-mTWTp2LPP(F56~nq+i+JX*V)6R5!f7KyZgYFKjZMlbO`WfOB&#oJEG1K3C zJ*Z2sv32Pmzlj&3mfGCKKEr%BAyZ|XMAq%pUC1tqa=otETPmmP7;biNJN zM|MQRrRThRe9Rt(^f?HBI2=IS8o08S30eEHHDHlgC_uD(O+8Y?Edqep+S(F?M#RqG z9n0Dr4;U@eFZP>|guiLLzfW9w+cr@N2^LUH6dh2EbTy6s{;dl^0?-chl$4ZP&mye_ z)dSZc$kl~V46gDrtY>c9LGM3!sF1lBShL_})UEFmiX-a4@+4^w+Lv|FqD9Kvx8DPK z0O)sJ)kAuksiMr`GR?$+nhx(DIU|*z4r_N`F%*=0 z68rU2}aA~}bGfn?AEBzIJD>gVPEq13==S3!Ix9O;G6;Nl89+mK5Tk(K2jY9QcF zL0RKJFQkROcb5z2JR4_6gpieu+>EHSG#iR7vRbEK&9-xVeuL939 z+Ub@<{<%^;P!+Xcg8Bz;Wd7Svnc!L|I!Qik{|Q?15+0QJwry6!vl$r~1YcQNt^}d8 z-e7ZKLm+)7pmc4xH{r%9Q(x!9hgWZxy*JdH9z}`3#hUjz1H2>cvtmW6PYD9mQ3fO1 z_&1787QWX&$&xW;XujO=&6|F=wQoiHQj-1s>>x*UzpUK2!I0MZG|`7P1Sd zUdd)Kab}rkXCg*@eI1FR6DN3(kmf{;y2Bmd76i)HV|Uv|9vIMQSDu_4xi$S0f^IP4 z*?+f-i)#^N+}d_x{Hs314ZmAw&kXwPo9iDQ1`mSLi0o#!rwtaZL9ahO@zT2YprF7M zfPEKGNjT`$QgeojxS2X<@^4tciY>M!-ul==>^BW00W8)b;1GeWG#i|S_2i*mfZyDb z2I7gG0{zD`q+l}lonLc)Ml~wT`?;IOOJ9@+jb$kW23BO4n6)>iFE?(LQ=8~l4_u`& zl`#a)Y4FT`1fRKug{@M5Mn~^^3Bm;~qGm^q1)YzLwFoIupB@m$3FbwzVjGZLTHa9@ zgk0~zCU$2;tEAG6NHtx86Pib7c}Q{N5zM| zJ78id+7^w|pQH{gqGp&WUXO$&X8Lz4+uhclIzRE%=ojq|i2Nwf@^9j|^P{0{NRo{-7R_eD<{+AR$5$k>;h zou5q~AGEH?bA9lpV2&_955-5XGo8WTZ#N60l%FEE|zd( z*i4CKY6mcL6SN>n03(rDqhc`l&rl`6Q1yD9TzE?%9z2MjWez!Fd zF58v!^YSvht*3tNisA^O0$^5xLqlEX6bdDN7}iWZ+1ln`m{F&e^A_2qi>TrflapJH zq2~%n?IQWX?B?e7vBYP|_LJY`J2nToo;%aCX?^kSuB&HXw`CoJ2S<{M2nf+@ANTL@ z{7hl8PXyfSfyvRHl}blfQp77*mijA_9!nqQN02B4wdUBAqHjICHT9pRIb$AFw(8}$ z-X_(|5>e}gyen7U7dpPl`Smq{4JLt^B@YZ{-o;@TMfQXCLAqVuv5EzECXNB2WWqH} z9m)3sw6qT#)tic~MwM6LGI42Pnt8MRx#27Xw68WURB~oGue`QNzqA3|QZ0mwcY;l; zdCuPZqJ0|SHpFaoDu1G z+`5$?UJnTIK4TSQ`XYc=^-~8feJ9)&&Npd|9<7rrH{Et@Dks^)BPxgsH8tH^`ii}J zL#O#ayavI0;B&>$V^V#PE3I zw|9nl=Bx|yB_t1ED)Y9|`OnYpTKF7_g6!6cGzKD3RCtke4H0i5&S)xt)1>N5Szs@? zFgBnV4ybxr<{e-K8#jspZAr+QdwP45400L9DchC@?mrVBnw`C&uRi_~bUBxkhfUI7 zh>#^DC97&{cb)O-zKZWG0|)PoP;`TJ0Z`oG`a6}tZ-jd@e{$jis6nLZLgBZG(CFyI z#Cb#{WG)=|EH;v=!K?4`4(>t{KkH}y-5WPT!5BhU`=!Ircr}tD>VPkd?0XAJf+)H< zR8SDiqwTi?5k@WwmQM?aNyU30F~?KC!S$aHBRCn$Dz2g;0IHXadJhN)h{i`F6h7E; ze;@L@TfelKn>LqK1UlRT2_1#vQ5KXaEau=aRoC7OJBdlQuxc9c^}ulJW!GJOC4ZvN z;LZF`&jDnZSF4^p)1zizK8BXl7hPxm>?dP_fpZYGY5+#5O@3ZL;&EcjiR{9)YrKqE z)WTI@i$)=%?f`N^+5eXmSogER!7SO2JLhJ)=P!eYCN>wDVwySyPM}b4_wFXkLokIa zA;AebsmsXP6T!26-Aj+)<#4P%-kf`)-;k(vf>eTx#0qX69>>Fn)4R9si9+p6lCjk1 z;bEJ5Q_r72_k#KL_4OtA36zN@=wYxv3qkfVI*ur~|L2&Xv_=!g+RlG)Ex7~KLFhU< ziY^mU4TpAwz`==v%)Ryw>hgQxbt>Td8%s~0B8*bUBj+V;IrdSwQzGX8VzUZ?LZMy6 z4%EaV^OA%KCgBkgTQq+)^{Uy=zX~qOTch3TJNlUkd<`v07CDZi8*T4ROG`qHf6KFZl~`0!!II~FmMR5#p7E(g|P0R^p# z+LtkUVK7j&Zs^hbPAoZMs6u~**=7_qvxI2w>&Yn7PD^`85RmHr;^VAj>{8kM-_vWh zpX30F(|zpmDMIju#FK{G3t>5&6uut!ixiSt!OtH?>b(tzQLaQ<-?&!U?44mU{zLZO zUGnp?IEwZ4^{DWZKwi-4dvxZDGhMTz0-Q~3wW_o;e8|;;BYFwT5aE&ZT_z0-~t4Dj;vRE|w z_H9D?SV$r4KY#V=)tF=jK?4oFbs(#WXG80Mt220VloP~r-TN2%-vyyDv8zLXg!}IS zi5%VCK{SwykErkL6hO{O;p9rmvuuk8W##2L!4@6jCMglVw|Ei%(sgi1%+uP$rchb; zC*v}J1t+A8k)avW^v1_OS_x``=;mVGUVOdBhg)zK2I-L7oi2U<0 literal 0 HcmV?d00001 diff --git a/tests/vis/test_fleur_vis.py b/tests/vis/test_fleur_vis.py index 3ec3df72c..d883d3c74 100644 --- a/tests/vis/test_fleur_vis.py +++ b/tests/vis/test_fleur_vis.py @@ -717,6 +717,33 @@ def test_plot_spinpol_dos_param_change_by_label_omit_spin(): return gcf() +@pytest.mark.mpl_image_compare(baseline_dir=MPL_BASELINE_DIR, filename='spinpol_dos_custom_plot_keys.png') +def test_plot_spinpol_dos_plot_keys_and_kwargs_custom_weight(): + from masci_tools.io.parsers.hdf5 import HDF5Reader + from masci_tools.io.parsers.hdf5.recipes import FleurDOS + from masci_tools.vis.fleur import plot_fleur_dos + + TEST_BANDDOS_FILE = os.path.join(HDFTEST_DIR, 'banddos_spinpol_dos.hdf') + + with HDF5Reader(TEST_BANDDOS_FILE) as h5reader: + data, attributes = h5reader.read(recipe=FleurDOS) + + gcf().clear() + + data['Custom_up'] = data['MT:1f_up'] * 0.5 + data['Custom_down'] = data['MT:1f_down'] * 0.5 + + plot_fleur_dos(data, + attributes, + show=False, + color={'Custom': 'red'}, + linestyle={'Custom': '--'}, + area_alpha=0.3, + plot_keys=['Custom']) + + return gcf() + + @pytest.mark.mpl_image_compare(baseline_dir=MPL_BASELINE_DIR, filename='bands_weighted_log_scale_colorbar.png') def test_plot_bands_weighted_log_scale_colorbar_mpl(): from masci_tools.io.parsers.hdf5 import HDF5Reader From 73054be2dbab01c03db9c464a56a754be4487ec3 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 29 Nov 2022 15:50:47 +0100 Subject: [PATCH 06/19] Add changelog entry --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2046e6665..4cf2a474a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,12 @@ ## latest [full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.13.0...develop) -Nothing here yet +### Bugfixes +- Serveral fixes for Fleur DOS plots [[#212]](https://github.com/JuDFTteam/masci-tools/pull/212): + - Fixed wrong summation of atom weights for files containing 10 or more atomtypes + - Fixed crashes using a custom weight not conforming to the naming scheme of weights in the `banddos.hdf` + - Fixed specification of parameters by DOS label not working if the spin suffix is omitted + ## v.0.13.0 [full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.12.0...v0.13.0) From 39695127e54d99c8d2629f857363be21a133acbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20R=C3=BCssmann?= Date: Thu, 1 Dec 2022 11:19:31 +0100 Subject: [PATCH 07/19] Move some standalone from util to tools (tools are standalone tools, utilities are used throughout the package or in other python code) --- masci_tools/{util => tools}/kkr_rms_tracker.py | 0 masci_tools/{util => tools}/modifypotential.py | 0 masci_tools/{util => tools}/plot_shapfun.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename masci_tools/{util => tools}/kkr_rms_tracker.py (100%) rename masci_tools/{util => tools}/modifypotential.py (100%) rename masci_tools/{util => tools}/plot_shapfun.py (100%) diff --git a/masci_tools/util/kkr_rms_tracker.py b/masci_tools/tools/kkr_rms_tracker.py similarity index 100% rename from masci_tools/util/kkr_rms_tracker.py rename to masci_tools/tools/kkr_rms_tracker.py diff --git a/masci_tools/util/modifypotential.py b/masci_tools/tools/modifypotential.py similarity index 100% rename from masci_tools/util/modifypotential.py rename to masci_tools/tools/modifypotential.py diff --git a/masci_tools/util/plot_shapfun.py b/masci_tools/tools/plot_shapfun.py similarity index 100% rename from masci_tools/util/plot_shapfun.py rename to masci_tools/tools/plot_shapfun.py From e8e7d8a1ec5fe87579d1a685564fc30f50ce2688 Mon Sep 17 00:00:00 2001 From: Henning Janssen Date: Fri, 2 Dec 2022 19:09:34 +0100 Subject: [PATCH 08/19] Support magnetic moment definitions in inpgen IO (#213) It can be added to the atomsites if a sequence of dicts or namedtuples under the name `magnetic_moment` is passed (not normal tuples) and can be 'up', 'down', a single float or a list of three floats --- CHANGELOG.md | 4 + masci_tools/io/common_functions.py | 1 + masci_tools/io/fleur_inpgen.py | 72 ++++- masci_tools/util/xml/xml_getters.py | 47 +++- tests/files/fleur/Max-R6/inp_NiO.xml | 247 ++++++++++++++++++ tests/io/test_fleur_inpgen.py | 186 +++++++++++++ ...t_mag_mom_float_write_inpgen_roundtrip.txt | 13 + ...list_noco_angle_write_inpgen_roundtrip.txt | 10 + ...st_mag_mom_list_write_inpgen_roundtrip.txt | 11 + .../test_mag_mom_write_inpgen_roundtrip.txt | 11 + .../test_read_inpgen_file.yml | 2 + .../test_read_inpgen_file_comments.yml | 2 + .../test_read_inpgen_file_contents.yml | 2 + .../test_read_inpgen_file_econfig.yml | 2 + .../test_read_inpgen_file_film.yml | 3 + .../test_read_inpgen_file_handle.yml | 2 + .../test_read_inpgen_file_magmom_float.yml | 31 +++ .../test_read_inpgen_file_magmom_list.yml | 35 +++ .../test_read_inpgen_file_magmom_str.yml | 31 +++ .../test_read_inpgen_file_parameters.yml | 2 + .../test_read_inpgen_file_soc_qss.yml | 2 + .../test_write_inpgen_file_magmom_float.txt | 11 + .../test_write_inpgen_file_magmom_list.txt | 11 + .../test_write_inpgen_file_magmom_str.txt | 11 + .../test_get_structuredata_bulk.yml | 2 + .../test_get_structuredata_film.yml | 8 + .../test_get_structuredata_max4.yml | 8 + .../test_get_structuredata_no_relaxed.yml | 3 + .../test_get_structuredata_norm_kinds.yml | 6 + .../test_get_structuredata_output.yml | 2 + .../test_get_structuredata_relaxed.yml | 3 + 31 files changed, 757 insertions(+), 24 deletions(-) create mode 100644 tests/files/fleur/Max-R6/inp_NiO.xml create mode 100644 tests/io/test_fleur_inpgen/test_mag_mom_float_write_inpgen_roundtrip.txt create mode 100644 tests/io/test_fleur_inpgen/test_mag_mom_list_noco_angle_write_inpgen_roundtrip.txt create mode 100644 tests/io/test_fleur_inpgen/test_mag_mom_list_write_inpgen_roundtrip.txt create mode 100644 tests/io/test_fleur_inpgen/test_mag_mom_write_inpgen_roundtrip.txt create mode 100644 tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_float.yml create mode 100644 tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_list.yml create mode 100644 tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_str.yml create mode 100644 tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_float.txt create mode 100644 tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_list.txt create mode 100644 tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_str.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cf2a474a..ab0bbe90e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ ## latest [full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.13.0...develop) +### Improvements +- `write/read_fleur_inpgen` now supports the magnetic moment definitions in the inpgen input file introduced in MaX-6.1 (also the `scf` namelist) [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) +- `get_structuredata` also reads out the magnetic moments [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) + ### Bugfixes - Serveral fixes for Fleur DOS plots [[#212]](https://github.com/JuDFTteam/masci-tools/pull/212): - Fixed wrong summation of atom weights for files containing 10 or more atomtypes diff --git a/masci_tools/io/common_functions.py b/masci_tools/io/common_functions.py index dcd6ad689..485247209 100644 --- a/masci_tools/io/common_functions.py +++ b/masci_tools/io/common_functions.py @@ -652,6 +652,7 @@ class AtomSiteProperties(NamedTuple): position: list[float] #TODO could be made generic with VectorType symbol: str kind: str + magnetic_moment: Literal['up', 'down'] | float | list[float] | None = None def get_wigner_matrix(l: int, alpha: float, beta: float, gamma: float = 0.0, inverse: bool = False) -> np.ndarray: diff --git a/masci_tools/io/fleur_inpgen.py b/masci_tools/io/fleur_inpgen.py index 1ee56a9af..2b8df10e5 100644 --- a/masci_tools/io/fleur_inpgen.py +++ b/masci_tools/io/fleur_inpgen.py @@ -19,11 +19,12 @@ import os import copy import warnings +import numbers from typing import Iterable, Sequence, Any, cast try: - from typing import TypedDict + from typing import TypedDict, Literal except ImportError: - from typing_extensions import TypedDict + from typing_extensions import TypedDict, Literal #type: ignore[misc] from masci_tools.util.constants import PERIODIC_TABLE_ELEMENTS, BOHR_A from masci_tools.util.typing import FileLike @@ -50,6 +51,7 @@ 'soc': ['theta', 'phi'], 'qss': ['x', 'y', 'z'], 'kpt': ['nkpt', 'kpts', 'div1', 'div2', 'div3', 'tkb', 'tria', 'gamma'], + 'scf': ['itmax', 'alpha', 'precond'], 'title': [] } @@ -65,6 +67,7 @@ class AtomDictProperties(TypedDict, total=False): """ position: list[float] | tuple[float, float, float] | np.ndarray kind_name: str + magnetic_moment: Literal['up', 'down'] | float | list[float] | None class Kinds(TypedDict, total=False): @@ -86,6 +89,7 @@ def write_inpgen_file(cell: np.ndarray | list[list[float]], input_params: dict[str, Any] | None = None, significant_figures_cell: int = 9, significant_figures_positions: int = 10, + significant_figures_magnetic_moments: int = 4, convert_from_angstroem: bool = True) -> str | None: """Write an input file for the fleur inputgenerator 'inpgen' from given inputs @@ -162,9 +166,18 @@ def write_inpgen_file(cell: np.ndarray | list[list[float]], symbols = [[kind['symbols'][0]] for site in atom_sites for kind in kinds if kind['name'] == site['kind_name']] if any(len(symbol) == 0 for symbol in symbols): raise ValueError('Failed getting symbols for all kinds. Check that all needed kinds are given') + + magnetic_moments = [s.get('magnetic_moment') for s in atom_sites] + + #yapf: disable + magnetic_moments = [list(m) if not isinstance(m, (numbers.Real, str, type(None))) else m for m in magnetic_moments] #type: ignore[arg-type] + #yapf: enable + atom_sites = [ - AtomSiteProperties(position=list(site['position']), symbol=kind[0], kind=site['kind_name']) - for site, kind in zip(atom_sites, symbols) + AtomSiteProperties(position=list(site['position']), + symbol=kind[0], + kind=site['kind_name'], + magnetic_moment=mag) for site, kind, mag in zip(atom_sites, symbols, magnetic_moments) ] elif any(not isinstance(site, AtomSiteProperties) for site in atom_sites): @@ -174,7 +187,6 @@ def write_inpgen_file(cell: np.ndarray | list[list[float]], #Workaround: cast(Sequence[AtomsiteProperties], atom_sites) does not work for some reason atom_sites = [cast(AtomSiteProperties, site) for site in atom_sites] - ########################################## ############# INPUT CHECK ################ ########################################## @@ -302,22 +314,32 @@ def write_inpgen_file(cell: np.ndarray | list[list[float]], vector_rel[2] = vector_rel[2] * scaling_pos position_str = ' '.join([f'{value:18.{significant_figures_positions}f}' for value in vector_rel]) + label = '' if site.symbol != site.kind: # This is an important fact, if user renames it becomes a new atomtype or species! - label = '' try: # Kind names can be more then numbers now, this might need to be reworked head = site.kind.rstrip('0123456789') kind_namet = int(site.kind[len(head):]) - #if int(kind_name[len(head)]) > 4: - # raise InputValidationError('New specie name/label should start with a digit smaller than 4') except ValueError: warnings.warn(f'Warning: Kind name {site.kind} will be ignored and not used to set a charge number.') else: atomic_number_name = f'{atomic_number}.{kind_namet}' label = str(kind_namet) - atom_positions_text.append(f' {atomic_number_name:>7} {position_str} {label}\n') - else: - atom_positions_text.append(f' {atomic_number_name:>7} {position_str}\n') + + atom_str = f' {atomic_number_name:>7} {position_str} {label}'.rstrip() + + if site.magnetic_moment is not None: + if isinstance(site.magnetic_moment, list): + magmom_str = ' '.join( + [f'{value:18.{significant_figures_magnetic_moments}f}' for value in site.magnetic_moment]) + atom_str = f'{atom_str} : {magmom_str}' + elif isinstance(site.magnetic_moment, float): + atom_str = f'{atom_str} : {site.magnetic_moment:18.{significant_figures_magnetic_moments}f}' + else: + atom_str = f'{atom_str} : {site.magnetic_moment}' + atom_str += '\n' + atom_positions_text.append(atom_str) + # TODO check format # we write it later, since we do not know what natoms is before the loop... atom_positions_str = f' {natoms:3}\n' + ''.join(atom_positions_text) @@ -602,9 +624,31 @@ def read_inpgen_file( else: kind_name = element - if len(atom_info) == 5: - kind_name = atom_info[4] + additional_info = ' '.join(atom_info[4:]) + + custom_kind, _, magmom_str = additional_info.partition(':') + custom_kind = custom_kind.strip() + if custom_kind: + kind_name = custom_kind + + magmom_str = magmom_str.strip() + magmom: Literal['up', 'down'] | float | list[float] | None = None + if magmom_str: + if magmom_str in ( + 'up', + 'down', + ): + magmom = magmom_str #type: ignore[assignment] + else: + magmom_list = magmom_str.split() + if len(magmom_list) == 1: + magmom = float(magmom_list[0]) + elif len(magmom_list) == 3: + magmom = [float(val) for val in magmom_list] + else: + raise ValueError(f'Invalid magnetic moment specification: {magmom_str}') - atom_sites.append(AtomSiteProperties(position=list(pos), symbol=element, kind=kind_name)) + atom_sites.append(AtomSiteProperties(position=list(pos), symbol=element, kind=kind_name, + magnetic_moment=magmom)) return cell, atom_sites, pbc, input_params diff --git a/masci_tools/util/xml/xml_getters.py b/masci_tools/util/xml/xml_getters.py index 7cf737898..fc9532389 100644 --- a/masci_tools/util/xml/xml_getters.py +++ b/masci_tools/util/xml/xml_getters.py @@ -25,7 +25,7 @@ import warnings import numpy as np from logging import Logger -from typing import Any +from typing import Any, cast from .xpathbuilder import FilterType @@ -291,7 +291,7 @@ def get_cell(xmltree: XMLLike, def _get_species_info(xmltree: XMLLike, schema_dict: fleur_schema.InputSchemaDict | fleur_schema.OutputSchemaDict, - logger: Logger | None = None) -> dict[str, dict[str, str]]: + logger: Logger | None = None) -> dict[str, dict[str, str | float | None]]: """ Gets the species identifiers and information. Used to keep species information consistent between @@ -307,22 +307,33 @@ def _get_species_info(xmltree: XMLLike, """ import re + bmu: list[float | None] = [] with FleurXMLContext(xmltree, schema_dict, logger=logger) as root: names = root.attribute('name', contains='species', list_return=True) elements = root.attribute('element', contains='species', list_return=True) + if root.attribute('jspins') == 2: + for species in root.iter('species'): + mom: float | None = 0.0 + for state in species.iter('stateoccupation'): + mom += state.attribute('spinup') - state.attribute('spindown') + bmu.append(mom) + else: + bmu = [None] * len(names) + if len(names) != len(elements): raise ValueError( f'Failed to read in species names and elements. Got {len(names)} names and {len(elements)} elements') - species_info: dict[str, dict[str, str]] = {} - for name, element in zip(names, elements): + species_info: dict[str, dict[str, str | float | None]] = {} + for name, element, mom in zip(names, elements, bmu): #Check if the species name has a numerical id at the end (separated by - or .) #And add all of them first species_info[name] = {} species_info[name]['element'] = element species_info[name]['normed_name'] = name + species_info[name]['magnetic_moment'] = mom match = re.fullmatch(r'(.+[\-\.])([1-9]+)', name) if match: species_info[name]['id'] = match.group(2) @@ -331,13 +342,13 @@ def _get_species_info(xmltree: XMLLike, if 'id' not in info: element = info['element'] #Find the smallest id which is free - used_ids = { - int(val['id']) for name, val in species_info.items() if 'id' in val and val['element'] == element - } + #yapf: disable + used_ids = {int(val['id']) for name, val in species_info.items() if 'id' in val and val['element'] == element } #type: ignore[arg-type] + #yapf: enable possible_ids = range(1, max(used_ids, default=0) + 2) info['id'] = str(min(set(possible_ids) - set(used_ids))) #Just append the id to the normed name - info['normed_name'] += f"-{info['id']}" + info['normed_name'] += f"-{info['id']}" #type: ignore[operator] return species_info @@ -517,6 +528,7 @@ def get_structuredata(xmltree: XMLLike, include_relaxations: bool = True, convert_to_angstroem: bool = True, normalize_kind_name: bool = True, + extract_magnetic_moments: bool = True, logger: Logger | None = None, **kwargs: Any) -> tuple[list[AtomSiteProperties], np.ndarray, tuple[bool, bool, bool]]: """ @@ -548,6 +560,8 @@ def get_structuredata(xmltree: XMLLike, the resulting positions correspond to the relaxed structure :param logger: logger object for logging warnings, errors :param convert_to_angstroem: bool if True the bravais matrix is converted to angstroem + :param extract_magnetic_moments: bool, if True (default) the magnetic moments are also extracted and put + onto the `atom_data` output :returns: tuple containing the structure information @@ -661,7 +675,19 @@ def get_structuredata(xmltree: XMLLike, atom_positions[pos_indx] = list(np.array(atom_positions[pos_indx]) + np.array(site_displace)) group_species = group.attribute('species') - element = species_info[group_species]['element'] + mag_mom: None | float | list[float] = None + if extract_magnetic_moments: + mag_mom = species_info[group_species]['magnetic_moment'] #type: ignore[assignment] + if mag_mom is not None and root.attribute('l_noco', default=False): + alpha = group.attribute('alpha', contains='noco') + beta = group.attribute('beta', contains='noco') + + mag_mom = [ + mag_mom * np.sin(beta) * np.cos(alpha), mag_mom * np.sin(beta) * np.sin(alpha), + mag_mom * np.cos(beta) + ] + + element = cast(str, species_info[group_species]['element']) if normalize_kind_name: normed_name = species_info[group_species]['normed_name'] if normed_name != group_species: @@ -676,7 +702,8 @@ def get_structuredata(xmltree: XMLLike, group_species = normed_name atom_data.extend( - AtomSiteProperties(position=pos, symbol=element, kind=group_species) for pos in atom_positions) + AtomSiteProperties(position=pos, symbol=element, kind=group_species, magnetic_moment=mag_mom) + for pos in atom_positions) return atom_data, cell, pbc diff --git a/tests/files/fleur/Max-R6/inp_NiO.xml b/tests/files/fleur/Max-R6/inp_NiO.xml new file mode 100644 index 000000000..0b5ce6188 --- /dev/null +++ b/tests/files/fleur/Max-R6/inp_NiO.xml @@ -0,0 +1,247 @@ + + + + NiO bct uc (AFM1) + + + + + + + + + + + + + + + + + + 9.00/20.00 9.00/20.00 5.00/12.00 + 9.00/20.00 7.00/20.00 5.00/12.00 + 9.00/20.00 5.00/20.00 5.00/12.00 + 9.00/20.00 3.00/20.00 5.00/12.00 + 9.00/20.00 1.00/20.00 5.00/12.00 + 7.00/20.00 7.00/20.00 5.00/12.00 + 7.00/20.00 5.00/20.00 5.00/12.00 + 7.00/20.00 3.00/20.00 5.00/12.00 + 7.00/20.00 1.00/20.00 5.00/12.00 + 5.00/20.00 5.00/20.00 5.00/12.00 + 5.00/20.00 3.00/20.00 5.00/12.00 + 5.00/20.00 1.00/20.00 5.00/12.00 + 3.00/20.00 3.00/20.00 5.00/12.00 + 3.00/20.00 1.00/20.00 5.00/12.00 + 1.00/20.00 1.00/20.00 5.00/12.00 + 9.00/20.00 9.00/20.00 3.00/12.00 + 9.00/20.00 7.00/20.00 3.00/12.00 + 9.00/20.00 5.00/20.00 3.00/12.00 + 9.00/20.00 3.00/20.00 3.00/12.00 + 9.00/20.00 1.00/20.00 3.00/12.00 + 7.00/20.00 7.00/20.00 3.00/12.00 + 7.00/20.00 5.00/20.00 3.00/12.00 + 7.00/20.00 3.00/20.00 3.00/12.00 + 7.00/20.00 1.00/20.00 3.00/12.00 + 5.00/20.00 5.00/20.00 3.00/12.00 + 5.00/20.00 3.00/20.00 3.00/12.00 + 5.00/20.00 1.00/20.00 3.00/12.00 + 3.00/20.00 3.00/20.00 3.00/12.00 + 3.00/20.00 1.00/20.00 3.00/12.00 + 1.00/20.00 1.00/20.00 3.00/12.00 + 9.00/20.00 9.00/20.00 1.00/12.00 + 9.00/20.00 7.00/20.00 1.00/12.00 + 9.00/20.00 5.00/20.00 1.00/12.00 + 9.00/20.00 3.00/20.00 1.00/12.00 + 9.00/20.00 1.00/20.00 1.00/12.00 + 7.00/20.00 7.00/20.00 1.00/12.00 + 7.00/20.00 5.00/20.00 1.00/12.00 + 7.00/20.00 3.00/20.00 1.00/12.00 + 7.00/20.00 1.00/20.00 1.00/12.00 + 5.00/20.00 5.00/20.00 1.00/12.00 + 5.00/20.00 3.00/20.00 1.00/12.00 + 5.00/20.00 1.00/20.00 1.00/12.00 + 3.00/20.00 3.00/20.00 1.00/12.00 + 3.00/20.00 1.00/20.00 1.00/12.00 + 1.00/20.00 1.00/20.00 1.00/12.00 + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + + + 5.6052356035999997 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 5.6052356035999997 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 7.9269999999999996 + + + + + + + + + (1s1/2) (2s1/2) (2p1/2) (2p3/2) (3s1/2) + (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + + (1s1/2) + (2s1/2) (2p1/2) (2p3/2) + + + + + + + + + + (1s1/2) (2s1/2) (2p1/2) (2p3/2) (3s1/2) + (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + 1.000/2.000 1.000/2.000 .0000000000 + + + + 1.000/2.000 1.000/2.000 1.000/2.000 + + + + .0000000000 .0000000000 1.000/2.000 + + + + + + + + + + + + + + + + + + + + diff --git a/tests/io/test_fleur_inpgen.py b/tests/io/test_fleur_inpgen.py index f88badf5c..8c1063402 100644 --- a/tests/io/test_fleur_inpgen.py +++ b/tests/io/test_fleur_inpgen.py @@ -31,6 +31,84 @@ def test_write_inpgen_file_defaults_dict(file_regression): file_regression.check(content) +def test_write_inpgen_file_magmom_str(file_regression): + + from masci_tools.io.fleur_inpgen import write_inpgen_file + + param = 5.43 + cell = [[0, param / 2., param / 2.], [param / 2., 0, param / 2.], [param / 2., param / 2., 0]] + kinds = [{'symbols': ('Si',), 'weights': (1.0,), 'mass': 28.0855, 'name': 'Si'}] + sites = [{ + 'position': (0.0, 0.0, 0.0), + 'kind_name': 'Si', + 'magnetic_moment': 'up' + }, { + 'position': (1.3575, 1.3575, 1.3575), + 'kind_name': 'Si', + 'magnetic_moment': 'down' + }] + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, sites, kinds, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) + + +def test_write_inpgen_file_magmom_float(file_regression): + + from masci_tools.io.fleur_inpgen import write_inpgen_file + + param = 5.43 + cell = [[0, param / 2., param / 2.], [param / 2., 0, param / 2.], [param / 2., param / 2., 0]] + kinds = [{'symbols': ('Si',), 'weights': (1.0,), 'mass': 28.0855, 'name': 'Si'}] + sites = [{ + 'position': (0.0, 0.0, 0.0), + 'kind_name': 'Si', + 'magnetic_moment': 1 + }, { + 'position': (1.3575, 1.3575, 1.3575), + 'kind_name': 'Si', + 'magnetic_moment': 2 + }] + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, sites, kinds, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) + + +def test_write_inpgen_file_magmom_list(file_regression): + + from masci_tools.io.fleur_inpgen import write_inpgen_file + + param = 5.43 + cell = [[0, param / 2., param / 2.], [param / 2., 0, param / 2.], [param / 2., param / 2., 0]] + kinds = [{'symbols': ('Si',), 'weights': (1.0,), 'mass': 28.0855, 'name': 'Si'}] + sites = [{ + 'position': (0.0, 0.0, 0.0), + 'kind_name': 'Si', + 'magnetic_moment': [1, 2, 3] + }, { + 'position': (1.3575, 1.3575, 1.3575), + 'kind_name': 'Si', + 'magnetic_moment': [4, 5, 6] + }] + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, sites, kinds, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) + + def test_write_inpgen_file_defaults_dict_filename(file_regression): from masci_tools.io.fleur_inpgen import write_inpgen_file @@ -470,6 +548,51 @@ def test_read_inpgen_file_comments(datadir, data_regression): }) +def test_read_inpgen_file_magmom_str(datadir, data_regression): + from masci_tools.io.fleur_inpgen import read_inpgen_file + + TESTFILE = datadir / 'test_write_inpgen_file_magmom_str.txt' + + cell, atom_sites, pbc, input_params = read_inpgen_file(TESTFILE) + + data_regression.check({ + 'cell': convert_to_pystd(cell), + 'atom_sites': [tuple(convert_to_pystd(site)) for site in atom_sites], + 'pbc': pbc, + 'params': convert_to_pystd(input_params) + }) + + +def test_read_inpgen_file_magmom_float(datadir, data_regression): + from masci_tools.io.fleur_inpgen import read_inpgen_file + + TESTFILE = datadir / 'test_write_inpgen_file_magmom_float.txt' + + cell, atom_sites, pbc, input_params = read_inpgen_file(TESTFILE) + + data_regression.check({ + 'cell': convert_to_pystd(cell), + 'atom_sites': [tuple(convert_to_pystd(site)) for site in atom_sites], + 'pbc': pbc, + 'params': convert_to_pystd(input_params) + }) + + +def test_read_inpgen_file_magmom_list(datadir, data_regression): + from masci_tools.io.fleur_inpgen import read_inpgen_file + + TESTFILE = datadir / 'test_write_inpgen_file_magmom_list.txt' + + cell, atom_sites, pbc, input_params = read_inpgen_file(TESTFILE) + + data_regression.check({ + 'cell': convert_to_pystd(cell), + 'atom_sites': [tuple(convert_to_pystd(site)) for site in atom_sites], + 'pbc': pbc, + 'params': convert_to_pystd(input_params) + }) + + def test_get_parameter_write_inpgen_roundtrip(file_regression, load_inpxml): """ Test that the get_parameterdata and get_structuredata methods produces the right inpgen input @@ -490,3 +613,66 @@ def test_get_parameter_write_inpgen_roundtrip(file_regression, load_inpxml): content = tmp.read() file_regression.check(content) + + +def test_mag_mom_list_write_inpgen_roundtrip(file_regression, load_inpxml): + """ + Test that the get_structuredata methods produces the right inpgen input with noco angles + to produce the right roundtrip + """ + from masci_tools.io.fleur_inpgen import write_inpgen_file + from masci_tools.util.xml.xml_getters import get_structuredata + + xmltree, schema_dict = load_inpxml('fleur/Max-R5/Fe_bctXML/files/inp.xml', absolute=False) + + atoms, cell, pbc = get_structuredata(xmltree, schema_dict) + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, atoms, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) + + +def test_mag_mom_float_write_inpgen_roundtrip(file_regression, load_inpxml): + """ + Test that the get_structuredata methods produces the right inpgen input with collinear setup + to produce the right roundtrip + """ + from masci_tools.io.fleur_inpgen import write_inpgen_file + from masci_tools.util.xml.xml_getters import get_structuredata + + xmltree, schema_dict = load_inpxml('fleur/Max-R6/inp_NiO.xml', absolute=False) + + atoms, cell, pbc = get_structuredata(xmltree, schema_dict) + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, atoms, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) + + +def test_mag_mom_list_noco_angle_write_inpgen_roundtrip(file_regression, load_inpxml): + """ + Test that the get_structuredata methods produces the right inpgen input with collinear setup + to produce the right roundtrip + """ + from masci_tools.io.fleur_inpgen import write_inpgen_file + from masci_tools.util.xml.xml_getters import get_structuredata + + xmltree, schema_dict = load_inpxml('fleur/Max-R5/Fe_fccXML/files/inp.xml', absolute=False) + + atoms, cell, pbc = get_structuredata(xmltree, schema_dict) + + with tempfile.TemporaryFile('w+') as tmp: + + write_inpgen_file(cell, atoms, file=tmp) + tmp.seek(0) + content = tmp.read() + + file_regression.check(content) diff --git a/tests/io/test_fleur_inpgen/test_mag_mom_float_write_inpgen_roundtrip.txt b/tests/io/test_fleur_inpgen/test_mag_mom_float_write_inpgen_roundtrip.txt new file mode 100644 index 000000000..e64628f2f --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_mag_mom_float_write_inpgen_roundtrip.txt @@ -0,0 +1,13 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 5.605235604 0.000000000 0.000000000 + 0.000000000 5.605235604 0.000000000 + 0.000000000 0.000000000 7.927000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 4 + 28.2 0.0000000000 0.0000000000 0.0000000000 2 : 1.1000 + 8.1 0.5000000000 0.5000000000 0.0000000000 1 : 0.0000 + 28.1 0.5000000000 0.5000000000 0.5000000000 1 : -1.1000 + 8.1 0.0000000000 0.0000000000 0.5000000000 1 : 0.0000 diff --git a/tests/io/test_fleur_inpgen/test_mag_mom_list_noco_angle_write_inpgen_roundtrip.txt b/tests/io/test_fleur_inpgen/test_mag_mom_list_noco_angle_write_inpgen_roundtrip.txt new file mode 100644 index 000000000..5f4ec2b74 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_mag_mom_list_noco_angle_write_inpgen_roundtrip.txt @@ -0,0 +1,10 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 0.000000000 3.410000000 3.410000000 + 3.410000000 0.000000000 3.410000000 + 3.410000000 3.410000000 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 1 + 26.1 0.0000000000 0.0000000000 0.0000000000 1 : 2.2000 0.0000 -0.0000 diff --git a/tests/io/test_fleur_inpgen/test_mag_mom_list_write_inpgen_roundtrip.txt b/tests/io/test_fleur_inpgen/test_mag_mom_list_write_inpgen_roundtrip.txt new file mode 100644 index 000000000..60f14bfe8 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_mag_mom_list_write_inpgen_roundtrip.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 4.822468380 0.000000000 0.000000000 + 0.000000000 4.822468380 0.000000000 + 0.000000000 0.000000000 6.820000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 26.1 0.0000000000 0.0000000000 0.0000000000 1 : 0.0000 0.0000 2.2000 + 26.2 0.5000000000 0.5000000000 0.5000000000 2 : 0.0000 0.0000 -2.2000 diff --git a/tests/io/test_fleur_inpgen/test_mag_mom_write_inpgen_roundtrip.txt b/tests/io/test_fleur_inpgen/test_mag_mom_write_inpgen_roundtrip.txt new file mode 100644 index 000000000..60f14bfe8 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_mag_mom_write_inpgen_roundtrip.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 4.822468380 0.000000000 0.000000000 + 0.000000000 4.822468380 0.000000000 + 0.000000000 0.000000000 6.820000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 26.1 0.0000000000 0.0000000000 0.0000000000 1 : 0.0000 0.0000 2.2000 + 26.2 0.5000000000 0.5000000000 0.5000000000 2 : 0.0000 0.0000 -2.2000 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file.yml index cdeb5d647..c1cefa6c0 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_comments.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_comments.yml index 8af71f264..c34d2ae73 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_comments.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_comments.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_contents.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_contents.yml index cdeb5d647..c1cefa6c0 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_contents.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_contents.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_econfig.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_econfig.yml index a3b8f3db0..f8f3a6aa3 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_econfig.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_econfig.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_film.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_film.yml index dda59b269..2395083d5 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_film.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_film.yml @@ -4,16 +4,19 @@ atom_sites: - 8.20885839049964 - Fe - Fe + - null - - - 0.0 - 0.0 - 10.096376717533458 - Nb - Nb + - null - - - 1.6584398382123395 - 0.0 - 12.468322058298224 - Nb - Nb + - null cell: - - 3.316879676424679 - 0.0 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_handle.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_handle.yml index cdeb5d647..c1cefa6c0 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_handle.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_handle.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_float.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_float.yml new file mode 100644 index 000000000..63d38866e --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_float.yml @@ -0,0 +1,31 @@ +atom_sites: +- - - 0.0 + - 0.0 + - 0.0 + - Si + - Si + - 1.0 +- - - 1.3574999999053843 + - 1.3574999999053843 + - 1.3574999999053843 + - Si + - Si + - 2.0 +cell: +- - 0.0 + - 2.7149999998107686 + - 2.7149999998107686 +- - 2.7149999998107686 + - 0.0 + - 2.7149999998107686 +- - 2.7149999998107686 + - 2.7149999998107686 + - 0.0 +params: + input: + cartesian: false + title: A Fleur input generator calculation with aiida +pbc: +- true +- true +- true diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_list.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_list.yml new file mode 100644 index 000000000..fdfd48748 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_list.yml @@ -0,0 +1,35 @@ +atom_sites: +- - - 0.0 + - 0.0 + - 0.0 + - Si + - Si + - - 1.0 + - 2.0 + - 3.0 +- - - 1.3574999999053843 + - 1.3574999999053843 + - 1.3574999999053843 + - Si + - Si + - - 4.0 + - 5.0 + - 6.0 +cell: +- - 0.0 + - 2.7149999998107686 + - 2.7149999998107686 +- - 2.7149999998107686 + - 0.0 + - 2.7149999998107686 +- - 2.7149999998107686 + - 2.7149999998107686 + - 0.0 +params: + input: + cartesian: false + title: A Fleur input generator calculation with aiida +pbc: +- true +- true +- true diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_str.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_str.yml new file mode 100644 index 000000000..dd6e2ac96 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_magmom_str.yml @@ -0,0 +1,31 @@ +atom_sites: +- - - 0.0 + - 0.0 + - 0.0 + - Si + - Si + - up +- - - 1.3574999999053843 + - 1.3574999999053843 + - 1.3574999999053843 + - Si + - Si + - down +cell: +- - 0.0 + - 2.7149999998107686 + - 2.7149999998107686 +- - 2.7149999998107686 + - 0.0 + - 2.7149999998107686 +- - 2.7149999998107686 + - 2.7149999998107686 + - 0.0 +params: + input: + cartesian: false + title: A Fleur input generator calculation with aiida +pbc: +- true +- true +- true diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_parameters.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_parameters.yml index 8af71f264..c34d2ae73 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_parameters.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_parameters.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_read_inpgen_file_soc_qss.yml b/tests/io/test_fleur_inpgen/test_read_inpgen_file_soc_qss.yml index d44296ebd..d33f7bbad 100644 --- a/tests/io/test_fleur_inpgen/test_read_inpgen_file_soc_qss.yml +++ b/tests/io/test_fleur_inpgen/test_read_inpgen_file_soc_qss.yml @@ -4,11 +4,13 @@ atom_sites: - 0.0 - Si - Si + - null - - - 1.3574999999053843 - 1.3574999999053843 - 1.3574999999053843 - Si - Si + - null cell: - - 0.0 - 2.7149999998107686 diff --git a/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_float.txt b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_float.txt new file mode 100644 index 000000000..d57a4060c --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_float.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 0.000000000 5.130606429 5.130606429 + 5.130606429 0.000000000 5.130606429 + 5.130606429 5.130606429 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 14 0.0000000000 0.0000000000 0.0000000000 : 1 + 14 0.2500000000 0.2500000000 0.2500000000 : 2 diff --git a/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_list.txt b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_list.txt new file mode 100644 index 000000000..f5a9afc06 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_list.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 0.000000000 5.130606429 5.130606429 + 5.130606429 0.000000000 5.130606429 + 5.130606429 5.130606429 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 14 0.0000000000 0.0000000000 0.0000000000 : 1.0000 2.0000 3.0000 + 14 0.2500000000 0.2500000000 0.2500000000 : 4.0000 5.0000 6.0000 diff --git a/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_str.txt b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_str.txt new file mode 100644 index 000000000..b6ddc6814 --- /dev/null +++ b/tests/io/test_fleur_inpgen/test_write_inpgen_file_magmom_str.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 0.000000000 5.130606429 5.130606429 + 5.130606429 0.000000000 5.130606429 + 5.130606429 5.130606429 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 14 0.0000000000 0.0000000000 0.0000000000 : up + 14 0.2500000000 0.2500000000 0.2500000000 : down diff --git a/tests/xml/test_xml_getters/test_get_structuredata_bulk.yml b/tests/xml/test_xml_getters/test_get_structuredata_bulk.yml index 23432d626..1b82a14cf 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_bulk.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_bulk.yml @@ -1,11 +1,13 @@ atoms: - kind: Si-1 + magnetic_moment: null position: - 0.6787502783660522 - 0.6787502783660522 - 0.6787502783660522 symbol: Si - kind: Si-1 + magnetic_moment: null position: - -0.6787502783660522 - -0.6787502783660522 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_film.yml b/tests/xml/test_xml_getters/test_get_structuredata_film.yml index bba9af42d..7549786cb 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_film.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_film.yml @@ -1,11 +1,19 @@ atoms: - kind: Fe-1 + magnetic_moment: + - 4.0 + - 0.0 + - 3.1795866169001593e-09 position: - 0.0 - 0.0 - -0.5272854045997698 symbol: Fe - kind: Pt-1 + magnetic_moment: + - 1.0 + - 0.0 + - 7.948966542250398e-10 position: - 1.4026317445650973 - 1.983620783415224 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_max4.yml b/tests/xml/test_xml_getters/test_get_structuredata_max4.yml index bba9af42d..7549786cb 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_max4.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_max4.yml @@ -1,11 +1,19 @@ atoms: - kind: Fe-1 + magnetic_moment: + - 4.0 + - 0.0 + - 3.1795866169001593e-09 position: - 0.0 - 0.0 - -0.5272854045997698 symbol: Fe - kind: Pt-1 + magnetic_moment: + - 1.0 + - 0.0 + - 7.948966542250398e-10 position: - 1.4026317445650973 - 1.983620783415224 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_no_relaxed.yml b/tests/xml/test_xml_getters/test_get_structuredata_no_relaxed.yml index 92a7a80db..66801bdfa 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_no_relaxed.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_no_relaxed.yml @@ -1,17 +1,20 @@ atoms: - kind: O-1 + magnetic_moment: null position: - 0.0 - 0.42334176864000006 - 0.0 symbol: O - kind: H-1 + magnetic_moment: null position: - -0.63501265296 - -0.42334176864000006 - 0.0 symbol: H - kind: H-1 + magnetic_moment: null position: - 0.63501265296 - -0.42334176864000006 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_norm_kinds.yml b/tests/xml/test_xml_getters/test_get_structuredata_norm_kinds.yml index d97217466..41e623e75 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_norm_kinds.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_norm_kinds.yml @@ -1,35 +1,41 @@ atoms: - kind: Neodymium (Nd)-1 + magnetic_moment: 3.1 position: - 0.0 - 0.0 - 0.0 symbol: Nd - kind: Cobalt (Co)-1 + magnetic_moment: 1.5999999999999999 position: - 2.5084144513147795 - -1.448235138232681 - 0.0 symbol: Co - kind: Cobalt (Co)-1 + magnetic_moment: 1.5999999999999999 position: - -2.5084144513147795 - 1.448235138232681 - 0.0 symbol: Co - kind: Cobalt (Co)-1 + magnetic_moment: 1.5999999999999999 position: - 2.5086653178465643 - 0.0 - 1.9708227534890188 symbol: Co - kind: Cobalt (Co)-1 + magnetic_moment: 1.5999999999999999 position: - 1.2543326589232822 - 2.172569964345456 - 1.9708227534890188 symbol: Co - kind: Cobalt (Co)-1 + magnetic_moment: 1.5999999999999999 position: - -1.2543326589232822 - 2.172569964345456 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_output.yml b/tests/xml/test_xml_getters/test_get_structuredata_output.yml index 23432d626..1b82a14cf 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_output.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_output.yml @@ -1,11 +1,13 @@ atoms: - kind: Si-1 + magnetic_moment: null position: - 0.6787502783660522 - 0.6787502783660522 - 0.6787502783660522 symbol: Si - kind: Si-1 + magnetic_moment: null position: - -0.6787502783660522 - -0.6787502783660522 diff --git a/tests/xml/test_xml_getters/test_get_structuredata_relaxed.yml b/tests/xml/test_xml_getters/test_get_structuredata_relaxed.yml index 3256b7142..db309a94a 100644 --- a/tests/xml/test_xml_getters/test_get_structuredata_relaxed.yml +++ b/tests/xml/test_xml_getters/test_get_structuredata_relaxed.yml @@ -1,17 +1,20 @@ atoms: - kind: O-1 + magnetic_moment: null position: - 0.0 - 0.28194015712293097 - 0.0 symbol: O - kind: H-1 + magnetic_moment: null position: - -0.6969647140293769 - -0.34985939129261007 - 0.0 symbol: H - kind: H-1 + magnetic_moment: null position: - 0.6969647140293769 - -0.34985939129261007 From 2bc3e87381e3ac64713650074e953ddb134761cc Mon Sep 17 00:00:00 2001 From: Henning Janssen Date: Wed, 7 Dec 2022 16:42:50 +0100 Subject: [PATCH 09/19] Add Command `masci-tools convert-inpgen` (#215) command to use pymatgen or ase to convert arbitrary structure formats to inpgen files Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/cd.yml | 4 +- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 3 + masci_tools/cmdline/commands/__init__.py | 2 +- .../cmdline/commands/convert_inpgen.py | 51 ++++ masci_tools/io/cif2inp_ase.py | 5 + masci_tools/io/common_functions.py | 6 +- masci_tools/io/fleur_inpgen.py | 9 +- .../fleur_schema_parser_functions.py | 6 +- masci_tools/util/lockable_containers.py | 18 +- masci_tools/util/python_util.py | 2 +- masci_tools/util/xml/converters.py | 6 +- masci_tools/util/xml/xml_setters_xpaths.py | 2 +- pyproject.toml | 6 +- tests/cmdline/test_convert_inpgen.py | 95 +++++++ .../test_convert_inpgen.txt | 11 + .../test_convert_inpgen_ase.txt | 11 + .../test_convert_inpgen_cif.txt | 17 ++ tests/files/cif_files/Si.cif | 258 ++++++++++++++++++ 19 files changed, 488 insertions(+), 28 deletions(-) create mode 100644 masci_tools/cmdline/commands/convert_inpgen.py create mode 100644 tests/cmdline/test_convert_inpgen.py create mode 100644 tests/cmdline/test_convert_inpgen/test_convert_inpgen.txt create mode 100644 tests/cmdline/test_convert_inpgen/test_convert_inpgen_ase.txt create mode 100644 tests/cmdline/test_convert_inpgen/test_convert_inpgen_cif.txt create mode 100644 tests/files/cif_files/Si.cif diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index a3b04fde9..8db1694f3 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -112,10 +112,12 @@ jobs: matrix: python-version: ['3.10','3.9', '3.8'] experimental: [false] + extra-dependencies: ['testing,bokeh-plots,cmdline-extras'] pytest-cmdline: [''] include: - python-version: '3.7' experimental: false + extra-dependencies: 'testing,bokeh-plots' pytest-cmdline: '-o addopts="--cov=masci_tools --cov=tests --cov-report xml"' # include: # - python-version: '3.11-dev' @@ -145,7 +147,7 @@ jobs: - name: Install python dependencies run: | - pip install -e .[testing,bokeh-plots] + pip install -e .[${{ matrix.extra-dependencies }}] pip install pyhull - name: Run pytest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e088dd7ab..b5c3e5515 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,10 +107,12 @@ jobs: matrix: python-version: ['3.10','3.9', '3.8'] experimental: [false] + extra-dependencies: ['testing,bokeh-plots,cmdline-extras'] pytest-cmdline: [""] include: - python-version: '3.7' experimental: false + extra-dependencies: 'testing,bokeh-plots' pytest-cmdline: '-o addopts="--cov=masci_tools --cov=tests --cov-report xml"' #- python-version: '3.11.0-rc.2' # experimental: true @@ -148,7 +150,7 @@ jobs: - name: Install python dependencies run: | - pip install -e .[testing,bokeh-plots] + pip install -e .[${{ matrix.extra-dependencies }}] pip install pyhull - name: Run pytest diff --git a/CHANGELOG.md b/CHANGELOG.md index ab0bbe90e..ae9a00d47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## latest [full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.13.0...develop) +### Added +- Command `masci-tools convert-inpgen` to transform common structure formats, e.g. `cif` into inpgen files. Uses `ase` or `pymatgen` with the corresponding fleur plugins `ase-fleur` and `pymatgen-io-fleur` (install additional dependencies `cmdline-extras`)[[#215]](https://github.com/JuDFTteam/masci-tools/pull/215) + ### Improvements - `write/read_fleur_inpgen` now supports the magnetic moment definitions in the inpgen input file introduced in MaX-6.1 (also the `scf` namelist) [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) - `get_structuredata` also reads out the magnetic moments [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) diff --git a/masci_tools/cmdline/commands/__init__.py b/masci_tools/cmdline/commands/__init__.py index d8507871e..02c3a644c 100644 --- a/masci_tools/cmdline/commands/__init__.py +++ b/masci_tools/cmdline/commands/__init__.py @@ -1,4 +1,4 @@ """ Import all the command groups to include in the cli """ -from . import (fleur_schema, parse, plot, tools) +from . import (convert_inpgen, fleur_schema, parse, plot, tools) diff --git a/masci_tools/cmdline/commands/convert_inpgen.py b/masci_tools/cmdline/commands/convert_inpgen.py new file mode 100644 index 000000000..0bfa608c5 --- /dev/null +++ b/masci_tools/cmdline/commands/convert_inpgen.py @@ -0,0 +1,51 @@ +""" +CLI commands for converting common structure definition formats to fleur inpgen files +""" +from .root import cli +import click + +from pathlib import Path +import os + +from masci_tools.cmdline.utils import echo + +try: + import pymatgen + from pymatgen.core import Structure +except ImportError: + pymatgen = None + +try: + import ase + from ase.io import read, write +except ImportError: + ase = None + + +@cli.command('convert-inpgen') +@click.argument('input-file', type=click.Path(exists=True, path_type=Path, resolve_path=True)) +@click.argument('output-file', type=click.Path(path_type=Path, resolve_path=True)) +@click.option('-c', + '--converter', + type=click.Choice(['ase', 'pymatgen']), + help='Which library is used to read in the given file format', + default='pymatgen') +def convert_inpgen(input_file, output_file, converter): + """Convert the given file to an fleur inpgen file + """ + + input_file = os.fspath(input_file) + output_file = os.fspath(output_file) + + if converter == 'ase': + if ase is None: + echo.echo_critical('ase is not installed. Please install the packages ase and ase-fleur') + + atoms = read(input_file) + write(output_file, atoms, format='fleur-inpgen') + elif converter == 'pymatgen': + if pymatgen is None: + echo.echo_critical('pymatgen is not installed. Please install the packages pymatgen and pymatgen-io-fleur') + + struc = Structure.from_file(os.fspath(input_file)) + struc.to(output_file, fmt='fleur-inpgen') diff --git a/masci_tools/io/cif2inp_ase.py b/masci_tools/io/cif2inp_ase.py index 0d30b7138..4b94ca3bf 100644 --- a/masci_tools/io/cif2inp_ase.py +++ b/masci_tools/io/cif2inp_ase.py @@ -14,6 +14,11 @@ Independent utility script to convert cif file formats to input for the inpgen code Usage: `python cif2inp_ase.py ` """ +import warnings + +warnings.warn( + 'The cif2inp_ase.py script is deprecated. Use the command' + 'masci-tools convert-inpgen --converter ase', DeprecationWarning) import sys import ase.io diff --git a/masci_tools/io/common_functions.py b/masci_tools/io/common_functions.py index 485247209..2d60818a9 100644 --- a/masci_tools/io/common_functions.py +++ b/masci_tools/io/common_functions.py @@ -22,10 +22,10 @@ from typing import TypeAlias else: from typing_extensions import TypeAlias -try: +if sys.version_info >= (3, 8): from typing import Literal -except ImportError: - from typing_extensions import Literal #type:ignore[misc] +else: + from typing_extensions import Literal import numpy as np from collections.abc import Sequence from masci_tools.util.typing import FileLike diff --git a/masci_tools/io/fleur_inpgen.py b/masci_tools/io/fleur_inpgen.py index 2b8df10e5..218c27d80 100644 --- a/masci_tools/io/fleur_inpgen.py +++ b/masci_tools/io/fleur_inpgen.py @@ -20,11 +20,12 @@ import copy import warnings import numbers +import sys from typing import Iterable, Sequence, Any, cast -try: - from typing import TypedDict, Literal -except ImportError: - from typing_extensions import TypedDict, Literal #type: ignore[misc] +if sys.version_info >= (3, 8): + from typing import Literal, TypedDict +else: + from typing_extensions import Literal, TypedDict from masci_tools.util.constants import PERIODIC_TABLE_ELEMENTS, BOHR_A from masci_tools.util.typing import FileLike diff --git a/masci_tools/io/parsers/fleur_schema/fleur_schema_parser_functions.py b/masci_tools/io/parsers/fleur_schema/fleur_schema_parser_functions.py index b0cca95f9..2b2656c07 100644 --- a/masci_tools/io/parsers/fleur_schema/fleur_schema_parser_functions.py +++ b/masci_tools/io/parsers/fleur_schema/fleur_schema_parser_functions.py @@ -19,10 +19,10 @@ from functools import wraps from typing import Callable, NamedTuple, Any, overload from lxml import etree -try: +if sys.version_info >= (3, 8): from typing import Literal, TypedDict -except ImportError: - from typing_extensions import Literal, TypedDict #type: ignore[misc] +else: + from typing_extensions import Literal, TypedDict if sys.version_info >= (3, 10): from typing import TypeAlias else: diff --git a/masci_tools/util/lockable_containers.py b/masci_tools/util/lockable_containers.py index 4e625fe85..db7d9bdc6 100644 --- a/masci_tools/util/lockable_containers.py +++ b/masci_tools/util/lockable_containers.py @@ -29,8 +29,10 @@ S = TypeVar('S') """ Type variable for the key type of the dictionary """ -T = TypeVar('T') +T_co = TypeVar('T_co', covariant=True) """ Type variable for the value type of the dictionary """ +T = TypeVar('T') +""" Type variable for the value type of the list """ @contextmanager @@ -54,7 +56,7 @@ def LockContainer(lock_object: LockableList[Any] | LockableDict[Any, Any]) -> It lock_object._unfreeze() #pylint: disable=protected-access -class LockableDict(UserDict, Generic[S, T]): +class LockableDict(UserDict, Generic[S, T_co]): """ Subclass of UserDict, which can prevent modifications to itself. Raises `RuntimeError` if modification is attempted. @@ -73,7 +75,7 @@ class LockableDict(UserDict, Generic[S, T]): """ - def __init__(self, *args: dict[S, T], recursive: bool = True, **kwargs: T) -> None: + def __init__(self, *args: dict[S, T_co], recursive: bool = True, **kwargs: T_co) -> None: self._locked = False self._recursive = recursive super().__init__(*args, **kwargs) @@ -93,7 +95,7 @@ def __delitem__(self, key: S) -> None: self.__check_lock() super().__delitem__(key) - def __setitem__(self, key: S, value: T | LockableDict[S, T] | LockableList[T]) -> None: + def __setitem__(self, key: S, value: T_co | LockableDict[S, T_co] | LockableList[T_co]) -> None: self.__check_lock() if isinstance(value, list): super().__setitem__(key, LockableList(value, recursive=self._recursive)) @@ -122,17 +124,17 @@ def _unfreeze(self) -> None: self._locked = False - def get_unlocked(self) -> dict[S, T]: + def get_unlocked(self) -> dict[S, T_co]: """ Get copy of object with builtin lists and dicts """ if self._recursive: - ret_dict: dict[S, T] = {} + ret_dict: dict[S, T_co] = {} for key, value in self.items(): if isinstance(value, LockableDict): - ret_dict[key] = cast(T, value.get_unlocked()) + ret_dict[key] = cast(T_co, value.get_unlocked()) elif isinstance(value, LockableList): - ret_dict[key] = cast(T, value.get_unlocked()) + ret_dict[key] = cast(T_co, value.get_unlocked()) else: ret_dict[key] = value else: diff --git a/masci_tools/util/python_util.py b/masci_tools/util/python_util.py index 909a9fa00..e0b69a661 100644 --- a/masci_tools/util/python_util.py +++ b/masci_tools/util/python_util.py @@ -272,7 +272,7 @@ def default(self, o: _typing.Any) -> _typing.Any: # pylint: disable=arguments-d return super().default(o) def encode(self, o: _typing.Any) -> str: # pylint: disable=arguments-differ - from _ctypes import PyObj_FromPtr #type: ignore[import] + from _ctypes import PyObj_FromPtr #type: ignore[attr-defined] format_spec = self.FORMAT_SPEC # Local var to expedite access. json_repr = super().encode(o) # Default JSON. diff --git a/masci_tools/util/xml/converters.py b/masci_tools/util/xml/converters.py index c16d2f9f6..2dee54450 100644 --- a/masci_tools/util/xml/converters.py +++ b/masci_tools/util/xml/converters.py @@ -20,10 +20,10 @@ from typing import TypeAlias else: from typing_extensions import TypeAlias -try: +if sys.version_info >= (3, 8): from typing import Literal -except ImportError: - from typing_extensions import Literal #type: ignore[misc] +else: + from typing_extensions import Literal from lxml import etree import logging from masci_tools.io.parsers import fleur_schema diff --git a/masci_tools/util/xml/xml_setters_xpaths.py b/masci_tools/util/xml/xml_setters_xpaths.py index b597eb0fc..5dfea690d 100644 --- a/masci_tools/util/xml/xml_setters_xpaths.py +++ b/masci_tools/util/xml/xml_setters_xpaths.py @@ -437,7 +437,7 @@ def xml_add_number_to_attrib(xmltree: XMLLike, if 'float' in types or 'float_expression' in types: new_values = values elif 'int' in types: - if any(not value.is_integer() for value in values): + if any(isinstance(value, float) and not value.is_integer() for value in values): raise ValueError('You are trying to write a float to an integer attribute') new_values = [int(value) for value in values] diff --git a/pyproject.toml b/pyproject.toml index 20d72712e..f47312b37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dependencies = [ [project.optional-dependencies] pre-commit = [ - 'mypy==0.971', + 'mypy==0.991', 'pre-commit>=2.6.0', 'yapf>=0.30.0', 'pylint~=2.14', @@ -74,7 +74,9 @@ bokeh-plots = [ 'bokeh' ] cmdline-extras = [ - 'python-gitlab' + 'python-gitlab', + 'pymatgen-io-fleur~=0.4,>=0.4.1', + #'ase-fleur' #Not yet available on pypi ] dev = [ 'bumpver' diff --git a/tests/cmdline/test_convert_inpgen.py b/tests/cmdline/test_convert_inpgen.py new file mode 100644 index 000000000..37cc94e4b --- /dev/null +++ b/tests/cmdline/test_convert_inpgen.py @@ -0,0 +1,95 @@ +""" +Tests of the commands in the convert-inpgen command of the masci-tools cli +""" +import os +import pytest + +try: + import pymatgen + from pymatgen.io.fleur import FleurInput +except ImportError: + pymatgen = None + +try: + import ase_fleur +except ImportError: + ase_fleur = None + + +@pytest.mark.skipif(not pymatgen, reason='pymatgen or pymatgen-io-fleur are not installed') +def test_pymatgen_converter(file_regression, test_file): + """ + Test of the convert-inpgen command using the pymatgen converter + """ + from masci_tools.cmdline.commands.convert_inpgen import convert_inpgen + from click.testing import CliRunner + + TEST_FILE = test_file('fleur/Max-R5/SiLOXML/files/inp.xml') + runner = CliRunner() + args = [TEST_FILE, 'inpgen.in', '--converter', 'pymatgen'] + with runner.isolated_filesystem(): + result = runner.invoke(convert_inpgen, args) + + print(result.output) + assert result.exception is None, f'An unexpected exception occurred: {result.exception}' + + assert os.path.isfile('inpgen.in') + + with open('inpgen.in', encoding='utf-8') as file: + content = file.read() + + file_regression.check(content, basename='test_convert_inpgen') + + +@pytest.mark.skipif(not pymatgen, reason='pymatgen or pymatgen-io-fleur are not installed') +def test_pymatgen_converter_cif(file_regression, test_file): + """ + Test of the convert-inpgen command using the pymatgen converter + """ + from masci_tools.cmdline.commands.convert_inpgen import convert_inpgen + from click.testing import CliRunner + + TEST_FILE = test_file('cif_files/Si.cif') + runner = CliRunner() + args = [TEST_FILE, 'inpgen.in', '--converter', 'pymatgen'] + with runner.isolated_filesystem(): + result = runner.invoke(convert_inpgen, args) + + print(result.output) + assert result.exception is None, f'An unexpected exception occurred: {result.exception}' + + assert os.path.isfile('inpgen.in') + + with open('inpgen.in', encoding='utf-8') as file: + content = file.read() + + #Protect against negative zeros + #The other tests do nothing with the numbers so negative zeros 'should' + #not appear + content = content.replace('-0.000000000', ' 0.000000000') + file_regression.check(content, basename='test_convert_inpgen_cif') + + +@pytest.mark.skipif(not ase_fleur, reason='ase-fleur is not installed') +def test_ase_converter(file_regression, test_file): + """ + Test of the convert-inpgen command using the ase converter + """ + from masci_tools.cmdline.commands.convert_inpgen import convert_inpgen + from click.testing import CliRunner + + TEST_FILE = test_file('fleur/Max-R5/SiLOXML/files/inp.xml') + runner = CliRunner() + args = [TEST_FILE, 'inpgen.in', '--converter', 'ase'] + with runner.isolated_filesystem(): + result = runner.invoke(convert_inpgen, args) + + print(result.output) + assert result.exception is None, f'An unexpected exception occurred: {result.exception}' + + assert os.path.isfile('inpgen.in') + + with open('inpgen.in', encoding='utf-8') as file: + content = file.read() + + file_regression.check(content, basename='test_convert_inpgen_ase') diff --git a/tests/cmdline/test_convert_inpgen/test_convert_inpgen.txt b/tests/cmdline/test_convert_inpgen/test_convert_inpgen.txt new file mode 100644 index 000000000..38064df0f --- /dev/null +++ b/tests/cmdline/test_convert_inpgen/test_convert_inpgen.txt @@ -0,0 +1,11 @@ +Si2 +&input cartesian=F / + 0.000000000 5.130608534 5.130608534 + 5.130608534 0.000000000 5.130608534 + 5.130608534 5.130608534 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 14 0.1250000000 0.1250000000 0.1250000000 + 14 -0.1250000000 -0.1250000000 -0.1250000000 diff --git a/tests/cmdline/test_convert_inpgen/test_convert_inpgen_ase.txt b/tests/cmdline/test_convert_inpgen/test_convert_inpgen_ase.txt new file mode 100644 index 000000000..30a45a851 --- /dev/null +++ b/tests/cmdline/test_convert_inpgen/test_convert_inpgen_ase.txt @@ -0,0 +1,11 @@ +A Fleur input generator calculation with aiida +&input cartesian=F / + 0.000000000 5.130608534 5.130608534 + 5.130608534 0.000000000 5.130608534 + 5.130608534 5.130608534 0.000000000 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 2 + 14 0.1250000000 0.1250000000 0.1250000000 + 14 -0.1250000000 -0.1250000000 -0.1250000000 diff --git a/tests/cmdline/test_convert_inpgen/test_convert_inpgen_cif.txt b/tests/cmdline/test_convert_inpgen/test_convert_inpgen_cif.txt new file mode 100644 index 000000000..868f978ce --- /dev/null +++ b/tests/cmdline/test_convert_inpgen/test_convert_inpgen_cif.txt @@ -0,0 +1,17 @@ +Si8 +&input cartesian=F / + 10.168616279 0.000000000 0.000000000 + 0.000000000 10.168616279 0.000000000 + 0.000000000 0.000000000 10.168616279 + 1.0000000000 + 1.000000000 1.000000000 1.000000000 + + 8 + 14 0.0000000000 0.0000000000 0.0000000000 + 14 0.2500000000 0.2500000000 0.2500000000 + 14 0.0000000000 0.5000000000 0.5000000000 + 14 0.7500000000 0.2500000000 0.7500000000 + 14 0.5000000000 0.0000000000 0.5000000000 + 14 0.2500000000 0.7500000000 0.7500000000 + 14 0.5000000000 0.5000000000 0.0000000000 + 14 0.7500000000 0.7500000000 0.2500000000 diff --git a/tests/files/cif_files/Si.cif b/tests/files/cif_files/Si.cif new file mode 100644 index 000000000..b76845a97 --- /dev/null +++ b/tests/files/cif_files/Si.cif @@ -0,0 +1,258 @@ +#------------------------------------------------------------------------------ +#$Date: 2018-09-27 07:13:35 +0300 (Thu, 27 Sep 2018) $ +#$Revision: 211196 $ +#$URL: file:///home/coder/svn-repositories/cod/cif/1/52/66/1526655.cif $ +#------------------------------------------------------------------------------ +# +# This file is available in the Crystallography Open Database (COD), +# http://www.crystallography.net/ +# +# All data on this site have been placed in the public domain by the +# contributors. +# +data_1526655 +loop_ +_publ_author_name +'Kitano, A.' +'Shintani, A.' +'Yonemura, M.' +'Moriguchi, K.' +'Yamanaka, S.' +'Fukuoka, H.' +'Munetoh, S.' +'Takata, M.' +'Nishibori, E.' +'Sakata, M.' +_publ_section_title +; + Structural properties and thermodynamic stability of Ba-doped silicon + type-I clathrates synthesized under high pressure +; +_journal_name_full +'Physical Review, Serie 3. B - Condensed Matter (18,1978-)' +_journal_page_first 0452061 +_journal_page_last 0452069 +_journal_volume 64 +_journal_year 2001 +_chemical_formula_sum Si +_space_group_IT_number 227 +_symmetry_space_group_name_Hall 'F 4d 2 3 -1d' +_symmetry_space_group_name_H-M 'F d -3 m :1' +_cell_angle_alpha 90 +_cell_angle_beta 90 +_cell_angle_gamma 90 +_cell_formula_units_Z 8 +_cell_length_a 5.381 +_cell_length_b 5.381 +_cell_length_c 5.381 +_cell_volume 155.808 +_citation_journal_id_ASTM PRBMDO +_cod_data_source_file Kitano_PRBMDO_2001_1900.cif +_cod_data_source_block Si1 +_cod_original_cell_volume 155.8077 +_cod_original_sg_symbol_Hall '-F 4vw 2vw 3 (x+1/8,y+1/8,z+1/8)' +_cod_original_formula_sum Si1 +_cod_database_code 1526655 +loop_ +_symmetry_equiv_pos_as_xyz +x,y,z +-y+1/4,x+1/4,z+1/4 +-x,-y+1/2,z+1/2 +y+3/4,-x+1/4,z+3/4 +x,-y+1/2,-z+1/2 +y+3/4,x+1/4,-z+3/4 +-x,y,-z +-y+1/4,-x+1/4,-z+1/4 +z,x,y +-x+1/4,z+1/4,y+1/4 +-z,-x+1/2,y+1/2 +x+3/4,-z+1/4,y+3/4 +z,-x+1/2,-y+1/2 +x+3/4,z+1/4,-y+3/4 +-z,x,-y +-x+1/4,-z+1/4,-y+1/4 +y,z,x +y+1/2,-z,-x+1/2 +z+1/4,y+3/4,-x+3/4 +-y+1/2,z+1/2,-x +-z+1/4,-y+3/4,-x+3/4 +-y+1/2,-z+1/2,x +z+1/4,-y+1/4,x+1/4 +-z+3/4,y+1/4,x+3/4 +-x+1/4,-y+1/4,-z+1/4 +y,-x,-z +x+1/4,y-1/4,-z-1/4 +-y-1/2,x,-z-1/2 +-x+1/4,y-1/4,z-1/4 +-y-1/2,-x,z-1/2 +x+1/4,-y+1/4,z+1/4 +y,x,z +-z+1/4,-x+1/4,-y+1/4 +x,-z,-y +z+1/4,x-1/4,-y-1/4 +-x-1/2,z,-y-1/2 +-z+1/4,x-1/4,y-1/4 +-x-1/2,-z,y-1/2 +z+1/4,-x+1/4,y+1/4 +x,z,y +-y+1/4,-z+1/4,-x+1/4 +-y-1/4,z+1/4,x-1/4 +-z,-y-1/2,x-1/2 +y-1/4,-z-1/4,x+1/4 +z,y-1/2,x-1/2 +y-1/4,z-1/4,-x+1/4 +-z,y,-x +z-1/2,-y,-x-1/2 +x,y+1/2,z+1/2 +-y+1/4,x+3/4,z+3/4 +-x,-y+1,z+1 +y+3/4,-x+3/4,z+5/4 +x,-y+1,-z+1 +y+3/4,x+3/4,-z+5/4 +-x,y+1/2,-z+1/2 +-y+1/4,-x+3/4,-z+3/4 +z,x+1/2,y+1/2 +-x+1/4,z+3/4,y+3/4 +-z,-x+1,y+1 +x+3/4,-z+3/4,y+5/4 +z,-x+1,-y+1 +x+3/4,z+3/4,-y+5/4 +-z,x+1/2,-y+1/2 +-x+1/4,-z+3/4,-y+3/4 +y,z+1/2,x+1/2 +y+1/2,-z+1/2,-x+1 +z+1/4,y+5/4,-x+5/4 +-y+1/2,z+1,-x+1/2 +-z+1/4,-y+5/4,-x+5/4 +-y+1/2,-z+1,x+1/2 +z+1/4,-y+3/4,x+3/4 +-z+3/4,y+3/4,x+5/4 +-x+1/4,-y+3/4,-z+3/4 +y,-x+1/2,-z+1/2 +x+1/4,y+1/4,-z+1/4 +-y-1/2,x+1/2,-z +-x+1/4,y+1/4,z+1/4 +-y-1/2,-x+1/2,z +x+1/4,-y+3/4,z+3/4 +y,x+1/2,z+1/2 +-z+1/4,-x+3/4,-y+3/4 +x,-z+1/2,-y+1/2 +z+1/4,x+1/4,-y+1/4 +-x-1/2,z+1/2,-y +-z+1/4,x+1/4,y+1/4 +-x-1/2,-z+1/2,y +z+1/4,-x+3/4,y+3/4 +x,z+1/2,y+1/2 +-y+1/4,-z+3/4,-x+3/4 +-y-1/4,z+3/4,x+1/4 +-z,-y,x +y-1/4,-z+1/4,x+3/4 +z,y,x +y-1/4,z+1/4,-x+3/4 +-z,y+1/2,-x+1/2 +z-1/2,-y+1/2,-x +x+1/2,y,z+1/2 +-y+3/4,x+1/4,z+3/4 +-x+1/2,-y+1/2,z+1 +y+5/4,-x+1/4,z+5/4 +x+1/2,-y+1/2,-z+1 +y+5/4,x+1/4,-z+5/4 +-x+1/2,y,-z+1/2 +-y+3/4,-x+1/4,-z+3/4 +z+1/2,x,y+1/2 +-x+3/4,z+1/4,y+3/4 +-z+1/2,-x+1/2,y+1 +x+5/4,-z+1/4,y+5/4 +z+1/2,-x+1/2,-y+1 +x+5/4,z+1/4,-y+5/4 +-z+1/2,x,-y+1/2 +-x+3/4,-z+1/4,-y+3/4 +y+1/2,z,x+1/2 +y+1,-z,-x+1 +z+3/4,y+3/4,-x+5/4 +-y+1,z+1/2,-x+1/2 +-z+3/4,-y+3/4,-x+5/4 +-y+1,-z+1/2,x+1/2 +z+3/4,-y+1/4,x+3/4 +-z+5/4,y+1/4,x+5/4 +-x+3/4,-y+1/4,-z+3/4 +y+1/2,-x,-z+1/2 +x+3/4,y-1/4,-z+1/4 +-y,x,-z +-x+3/4,y-1/4,z+1/4 +-y,-x,z +x+3/4,-y+1/4,z+3/4 +y+1/2,x,z+1/2 +-z+3/4,-x+1/4,-y+3/4 +x+1/2,-z,-y+1/2 +z+3/4,x-1/4,-y+1/4 +-x,z,-y +-z+3/4,x-1/4,y+1/4 +-x,-z,y +z+3/4,-x+1/4,y+3/4 +x+1/2,z,y+1/2 +-y+3/4,-z+1/4,-x+3/4 +-y+1/4,z+1/4,x+1/4 +-z+1/2,-y-1/2,x +y+1/4,-z-1/4,x+3/4 +z+1/2,y-1/2,x +y+1/4,z-1/4,-x+3/4 +-z+1/2,y,-x+1/2 +z,-y,-x +x+1/2,y+1/2,z +-y+3/4,x+3/4,z+1/4 +-x+1/2,-y+1,z+1/2 +y+5/4,-x+3/4,z+3/4 +x+1/2,-y+1,-z+1/2 +y+5/4,x+3/4,-z+3/4 +-x+1/2,y+1/2,-z +-y+3/4,-x+3/4,-z+1/4 +z+1/2,x+1/2,y +-x+3/4,z+3/4,y+1/4 +-z+1/2,-x+1,y+1/2 +x+5/4,-z+3/4,y+3/4 +z+1/2,-x+1,-y+1/2 +x+5/4,z+3/4,-y+3/4 +-z+1/2,x+1/2,-y +-x+3/4,-z+3/4,-y+1/4 +y+1/2,z+1/2,x +y+1,-z+1/2,-x+1/2 +z+3/4,y+5/4,-x+3/4 +-y+1,z+1,-x +-z+3/4,-y+5/4,-x+3/4 +-y+1,-z+1,x +z+3/4,-y+3/4,x+1/4 +-z+5/4,y+3/4,x+3/4 +-x+3/4,-y+3/4,-z+1/4 +y+1/2,-x+1/2,-z +x+3/4,y+1/4,-z-1/4 +-y,x+1/2,-z-1/2 +-x+3/4,y+1/4,z-1/4 +-y,-x+1/2,z-1/2 +x+3/4,-y+3/4,z+1/4 +y+1/2,x+1/2,z +-z+3/4,-x+3/4,-y+1/4 +x+1/2,-z+1/2,-y +z+3/4,x+1/4,-y-1/4 +-x,z+1/2,-y-1/2 +-z+3/4,x+1/4,y-1/4 +-x,-z+1/2,y-1/2 +z+3/4,-x+3/4,y+1/4 +x+1/2,z+1/2,y +-y+3/4,-z+3/4,-x+1/4 +-y+1/4,z+3/4,x-1/4 +-z+1/2,-y,x-1/2 +y+1/4,-z+1/4,x+1/4 +z+1/2,y,x-1/2 +y+1/4,z+1/4,-x+1/4 +-z+1/2,y+1/2,-x +z,-y+1/2,-x-1/2 +loop_ +_atom_site_label +_atom_site_type_symbol +_atom_site_fract_x +_atom_site_fract_y +_atom_site_fract_z +_atom_site_occupancy +_atom_site_U_iso_or_equiv +Si1 Si 0 0 0 1 0.0 From 90926f42c5020b8a20794674292469040f994e53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 07:20:44 +0000 Subject: [PATCH 10/19] Bump actions/setup-python from 4.2.0 to 4.3.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.2.0 to 4.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4.2.0...v4.3.0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/cd.yml | 8 ++++---- .github/workflows/ci.yml | 6 +++--- .github/workflows/fleur-release.yml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 8db1694f3..46eb2724d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -31,7 +31,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python 3.10 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: '3.10' @@ -90,7 +90,7 @@ jobs: pip-pre-commit- - name: Set up Python 3.8 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: 3.8 @@ -140,7 +140,7 @@ jobs: pip-${{ matrix.python-version }}-tests - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ matrix.python-version }} @@ -172,7 +172,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Set up Python 3.7 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: 3.7 - name: Install flit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5c3e5515..ec6e3676f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python 3.10 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: '3.10' @@ -84,7 +84,7 @@ jobs: pip-pre-commit- - name: Set up Python 3.8 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: 3.8 @@ -135,7 +135,7 @@ jobs: pip-${{ matrix.python-version }}-tests - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/fleur-release.yml b/.github/workflows/fleur-release.yml index 711edb594..1535810bf 100644 --- a/.github/workflows/fleur-release.yml +++ b/.github/workflows/fleur-release.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python 3.8 - uses: actions/setup-python@v4.2.0 + uses: actions/setup-python@v4.3.0 with: python-version: 3.8 From ef93fc622eb3168b8a2a534fdf8e859b6f5ee36c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 07:38:29 +0000 Subject: [PATCH 11/19] Bump actions/cache from 3.0.6 to 3.0.9 Bumps [actions/cache](https://github.com/actions/cache) from 3.0.6 to 3.0.9. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.6...v3.0.9) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/cd.yml | 6 +++--- .github/workflows/ci.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 46eb2724d..2eddf1742 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -37,7 +37,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-docs-${{ hashFiles('**/pyproject.toml') }} @@ -82,7 +82,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-pre-commit-${{ hashFiles('**/pyproject.toml') }} @@ -132,7 +132,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-${{ matrix.python-version }}-tests-${{ hashFiles('**/pyproject.toml') }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec6e3676f..65f2b4a1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-docs-${{ hashFiles('**/pyproject.toml') }} @@ -76,7 +76,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-pre-commit-${{ hashFiles('**/pyproject.toml') }} @@ -127,7 +127,7 @@ jobs: - name: Cache python dependencies id: cache-pip - uses: actions/cache@v3.0.6 + uses: actions/cache@v3.0.9 with: path: ~/.cache/pip key: pip-${{ matrix.python-version }}-tests-${{ hashFiles('**/pyproject.toml') }} From f7b3cb15fb39a5046e8dca2679dcc0d408ab2598 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Oct 2022 07:38:25 +0000 Subject: [PATCH 12/19] Bump peter-evans/create-pull-request from 4.0.4 to 4.1.3 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.0.4 to 4.1.3. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v4.0.4...v4.1.3) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/fleur-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fleur-release.yml b/.github/workflows/fleur-release.yml index 1535810bf..2e812368a 100644 --- a/.github/workflows/fleur-release.yml +++ b/.github/workflows/fleur-release.yml @@ -40,7 +40,7 @@ jobs: run: exit 1 - name: Create Pull Request - uses: peter-evans/create-pull-request@v4.0.4 + uses: peter-evans/create-pull-request@v4.1.3 with: commit-message: "[fleur release] Fleur schema update" branch: fleur-release/schema From d720a181978d0975ad03c5a4c1bf739db0a5d848 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Dec 2022 17:20:19 +0000 Subject: [PATCH 13/19] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0) - https://github.com/ikamensh/flynt/: 0.76 → 0.77 - [github.com/asottile/pyupgrade: v2.37.3 → v3.3.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v3.3.0) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e4eef341c..52c05f81f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: double-quote-string-fixer types: [python] @@ -33,7 +33,7 @@ repos: additional_dependencies: ['toml'] - repo: https://github.com/ikamensh/flynt/ - rev: '0.76' + rev: '0.77' hooks: - id: flynt args: [ @@ -42,7 +42,7 @@ repos: ] - repo: https://github.com/asottile/pyupgrade - rev: v2.37.3 + rev: v3.3.0 hooks: - id: pyupgrade args: [ From 807d3957f8d54290989eabc49d083572cf1b095d Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 4 Dec 2022 10:16:40 +0100 Subject: [PATCH 14/19] Forgot to add scf to the valid namelists list --- masci_tools/io/fleur_inpgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/masci_tools/io/fleur_inpgen.py b/masci_tools/io/fleur_inpgen.py index 218c27d80..5bb1ef5e9 100644 --- a/masci_tools/io/fleur_inpgen.py +++ b/masci_tools/io/fleur_inpgen.py @@ -39,7 +39,7 @@ # Inpgen file structure, order is important POSSIBLE_NAMELISTS = [ 'title', 'input', 'lattice', 'gen', 'shift', 'factor', 'qss', 'soc', 'atom', 'comp', 'exco', 'expert', 'film', - 'kpt', 'end' + 'kpt', 'scf', 'end' ] POSSIBLE_PARAMS: dict[str, list[str]] = { 'input': ['film', 'cartesian', 'cal_symm', 'checkinp', 'symor', 'oldfleur'], From b58b2aa831546182a6a06dea98ad9abdc5845090 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 8 Dec 2022 10:46:46 +0100 Subject: [PATCH 15/19] Add functions to get and readd the inpgen comments from the XML tree can be used in aiida-fleur to persist these comments through the FleurinpModifier --- masci_tools/io/fleurxmlmodifier.py | 10 +- masci_tools/util/xml/common_functions.py | 46 ++++ tests/io/test_fleurxmlmodifier.py | 13 + ...urxml_modifier_include_inpgen_comments.xml | 246 ++++++++++++++++++ 4 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 tests/io/test_fleurxmlmodifier/test_fleurxml_modifier_include_inpgen_comments.xml diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 5b21b4b07..a973ce7dd 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -30,7 +30,7 @@ from masci_tools.util.xml.collect_xml_setters import XPATH_SETTERS, SCHEMA_DICT_SETTERS, NMMPMAT_SETTERS from masci_tools.util.xml.xml_setters_names import set_attrib_value -from masci_tools.util.xml.common_functions import clear_xml, eval_xpath_one +from masci_tools.util.xml.common_functions import clear_xml, eval_xpath_one, get_inpgen_comments, readd_inpgen_comments from masci_tools.util.schema_dict_util import ensure_relaxation_xinclude from masci_tools.io.fleur_xml import load_inpxml from masci_tools.util.typing import XMLFileLike, FileLike @@ -364,7 +364,8 @@ def modify_xmlfile(self, original_inpxmlfile: XMLFileLike, original_nmmp_file: FileLike | list[str] | None = None, validate_changes: bool = True, - adjust_version_for_dev_version: bool = True) -> tuple[etree._ElementTree, dict[str, str]]: + adjust_version_for_dev_version: bool = True, + keep_inpgen_comments: bool = True) -> tuple[etree._ElementTree, dict[str, str]]: """ Applies the registered modifications to a given inputfile @@ -378,6 +379,7 @@ def modify_xmlfile(self, :returns: a modified xmltree and if existent a modified density matrix file """ original_xmltree, schema_dict = load_inpxml(original_inpxmlfile) + comments = get_inpgen_comments(original_xmltree) if original_nmmp_file is not None: if isinstance(original_nmmp_file, str) and not Path(original_nmmp_file).is_file(): @@ -398,6 +400,10 @@ def modify_xmlfile(self, adjust_version_for_dev_version=adjust_version_for_dev_version) ensure_relaxation_xinclude(new_xmltree, schema_dict) + + if keep_inpgen_comments: + readd_inpgen_comments(new_xmltree, comments) + etree.indent(new_xmltree) additional_files = {} diff --git a/masci_tools/util/xml/common_functions.py b/masci_tools/util/xml/common_functions.py index 5ab40e8db..f37f19860 100644 --- a/masci_tools/util/xml/common_functions.py +++ b/masci_tools/util/xml/common_functions.py @@ -105,6 +105,52 @@ def clear_xml(tree: etree._ElementTree) -> tuple[etree._ElementTree, set[str]]: return cleared_tree, all_included_tags +def get_inpgen_comments(xmltree: etree._ElementTree) -> list[etree._Element]: + """ + Get the XML comment element appended after the root of the inp.xml file + + These contain at the moment the inpgen command line and the content of the + inpgen file + + :param xmltree: representation of the inp.xml + + :returns: list of XML comments, which appear after the fleurInput tag + """ + + root = xmltree.getroot() + + comments = [] + next_sibling = root.getnext() + while next_sibling is not None: + next_elem = next_sibling.getnext() + if next_sibling.tag is etree.Comment: + comments.append(next_sibling) + next_sibling = next_elem + + return comments + + +def readd_inpgen_comments(xmltree: etree._ElementTree, comments: list[etree._Element]) -> etree._ElementTree: + """ + Add the given comments after the fleurInput tag of the inp.xml + + These contain at the moment the inpgen command line and the content of the + inpgen file + + :param xmltree: representation of the inp.xml + :param comments: list of XML comments + """ + + root = xmltree.getroot() + + for comment in comments: + if not comment.tag is etree.Comment: + raise ValueError(f'Invalid tag type. Only Comments allowed. Got: {comment.tag}') + root.addnext(comment) + + return xmltree + + def reverse_xinclude(xmltree, schema_dict, included_tags, **kwargs): """ DEPRECATED ALIAS: Moved to masci_tools.util.schema_dict_util diff --git a/tests/io/test_fleurxmlmodifier.py b/tests/io/test_fleurxmlmodifier.py index 28b63ac1a..751e7e367 100644 --- a/tests/io/test_fleurxmlmodifier.py +++ b/tests/io/test_fleurxmlmodifier.py @@ -8,6 +8,7 @@ TEST_INPXML_PATH = 'fleur/Max-R5/FePt_film_SSFT_LO/files/inp2.xml' TEST_INPXML_NEWER_PATH = 'fleur/input_newer_version.xml' TEST_INPXML_LDAU_PATH = 'fleur/Max-R5/GaAsMultiUForceXML/files/inp.xml' +TEST_INPXML_COMMENT_PATH = 'fleur/Max-R6/inp_NiO.xml' TEST_NMMPMAT_PATH = 'fleur/input_nmmpmat.txt' @@ -513,3 +514,15 @@ def test_fleurxml_modifier_modify_xmlfile_dev_version(test_file): with pytest.warns(UserWarning): with pytest.raises(ValueError): fm.modify_xmlfile(test_file(TEST_INPXML_NEWER_PATH), adjust_version_for_dev_version=False) + + +def test_fleurxml_modifier_include_inpgen_comments(test_file, file_regression): + """Tests if fleurinp_modifier keeps the inpgen comments correctly""" + + fm = FleurXMLModifier() + fm.set_inpchanges({'dos': True, 'Kmax': 3.9}) + + xmltree, add_files = fm.modify_xmlfile(test_file(TEST_INPXML_COMMENT_PATH)) + + assert len(add_files) == 0 + file_regression.check(etree.tostring(xmltree, encoding='unicode', pretty_print=True), extension='.xml') diff --git a/tests/io/test_fleurxmlmodifier/test_fleurxml_modifier_include_inpgen_comments.xml b/tests/io/test_fleurxmlmodifier/test_fleurxml_modifier_include_inpgen_comments.xml new file mode 100644 index 000000000..a7d98b3a7 --- /dev/null +++ b/tests/io/test_fleurxmlmodifier/test_fleurxml_modifier_include_inpgen_comments.xml @@ -0,0 +1,246 @@ + + + NiO bct uc (AFM1) + + + + + + + + + + + + + + + + + + 9.00/20.00 9.00/20.00 5.00/12.00 + 9.00/20.00 7.00/20.00 5.00/12.00 + 9.00/20.00 5.00/20.00 5.00/12.00 + 9.00/20.00 3.00/20.00 5.00/12.00 + 9.00/20.00 1.00/20.00 5.00/12.00 + 7.00/20.00 7.00/20.00 5.00/12.00 + 7.00/20.00 5.00/20.00 5.00/12.00 + 7.00/20.00 3.00/20.00 5.00/12.00 + 7.00/20.00 1.00/20.00 5.00/12.00 + 5.00/20.00 5.00/20.00 5.00/12.00 + 5.00/20.00 3.00/20.00 5.00/12.00 + 5.00/20.00 1.00/20.00 5.00/12.00 + 3.00/20.00 3.00/20.00 5.00/12.00 + 3.00/20.00 1.00/20.00 5.00/12.00 + 1.00/20.00 1.00/20.00 5.00/12.00 + 9.00/20.00 9.00/20.00 3.00/12.00 + 9.00/20.00 7.00/20.00 3.00/12.00 + 9.00/20.00 5.00/20.00 3.00/12.00 + 9.00/20.00 3.00/20.00 3.00/12.00 + 9.00/20.00 1.00/20.00 3.00/12.00 + 7.00/20.00 7.00/20.00 3.00/12.00 + 7.00/20.00 5.00/20.00 3.00/12.00 + 7.00/20.00 3.00/20.00 3.00/12.00 + 7.00/20.00 1.00/20.00 3.00/12.00 + 5.00/20.00 5.00/20.00 3.00/12.00 + 5.00/20.00 3.00/20.00 3.00/12.00 + 5.00/20.00 1.00/20.00 3.00/12.00 + 3.00/20.00 3.00/20.00 3.00/12.00 + 3.00/20.00 1.00/20.00 3.00/12.00 + 1.00/20.00 1.00/20.00 3.00/12.00 + 9.00/20.00 9.00/20.00 1.00/12.00 + 9.00/20.00 7.00/20.00 1.00/12.00 + 9.00/20.00 5.00/20.00 1.00/12.00 + 9.00/20.00 3.00/20.00 1.00/12.00 + 9.00/20.00 1.00/20.00 1.00/12.00 + 7.00/20.00 7.00/20.00 1.00/12.00 + 7.00/20.00 5.00/20.00 1.00/12.00 + 7.00/20.00 3.00/20.00 1.00/12.00 + 7.00/20.00 1.00/20.00 1.00/12.00 + 5.00/20.00 5.00/20.00 1.00/12.00 + 5.00/20.00 3.00/20.00 1.00/12.00 + 5.00/20.00 1.00/20.00 1.00/12.00 + 3.00/20.00 3.00/20.00 1.00/12.00 + 3.00/20.00 1.00/20.00 1.00/12.00 + 1.00/20.00 1.00/20.00 1.00/12.00 + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + + + 5.6052356035999997 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 5.6052356035999997 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 7.9269999999999996 + + + + + + + + + (1s1/2) (2s1/2) (2p1/2) (2p3/2) (3s1/2) + (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + + (1s1/2) + (2s1/2) (2p1/2) (2p3/2) + + + + + + + + + + (1s1/2) (2s1/2) (2p1/2) (2p3/2) (3s1/2) + (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + 1.000/2.000 1.000/2.000 .0000000000 + + + + 1.000/2.000 1.000/2.000 1.000/2.000 + + + + .0000000000 .0000000000 1.000/2.000 + + + + + + + + + + + + + + + + + + + + From 0ca2b60c2df99875f4e6968c61fa75a3cd285da5 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 8 Dec 2022 11:18:04 +0100 Subject: [PATCH 16/19] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae9a00d47..4172b6342 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ ### Added - Command `masci-tools convert-inpgen` to transform common structure formats, e.g. `cif` into inpgen files. Uses `ase` or `pymatgen` with the corresponding fleur plugins `ase-fleur` and `pymatgen-io-fleur` (install additional dependencies `cmdline-extras`)[[#215]](https://github.com/JuDFTteam/masci-tools/pull/215) +- Functions `get_inpgen_comments` and `readd_inpgen_comments` to keep the comments of the inp.xml file containing the inpgen commandline and file content through functions using `clear_xml` ### Improvements - `write/read_fleur_inpgen` now supports the magnetic moment definitions in the inpgen input file introduced in MaX-6.1 (also the `scf` namelist) [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) - `get_structuredata` also reads out the magnetic moments [[#213]](https://github.com/JuDFTteam/masci-tools/pull/213) +- `FleurXMLModifier.modify_xmlfile` now keeps the inpgen comments by default (controlled by option `keep_inpgen_comments`) ### Bugfixes - Serveral fixes for Fleur DOS plots [[#212]](https://github.com/JuDFTteam/masci-tools/pull/212): From 354a35f757096ca7a5600ece1daeb8187651da81 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 8 Dec 2022 12:20:13 +0100 Subject: [PATCH 17/19] bump version 0.13.0 -> 0.14.0 --- masci_tools/__init__.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/masci_tools/__init__.py b/masci_tools/__init__.py index 739e1b5b7..6c83bad03 100644 --- a/masci_tools/__init__.py +++ b/masci_tools/__init__.py @@ -21,7 +21,7 @@ __copyright__ = ('Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. ' 'All rights reserved.') __license__ = 'MIT license, see LICENSE.txt file.' -__version__ = '0.13.0' +__version__ = '0.14.0' __authors__ = 'The JuDFT team. Also see AUTHORS.txt file.' logging.getLogger(__name__).addHandler(logging.NullHandler()) diff --git a/pyproject.toml b/pyproject.toml index f47312b37..1e4fb825c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -210,7 +210,7 @@ split_arguments_when_comma_terminated = true indent_dictionary_value = false [bumpver] -current_version = "0.13.0" +current_version = "0.14.0" version_pattern = "MAJOR.MINOR.PATCH[TAGNUM]" commit_message = "bump version {old_version} -> {new_version}" commit = true From 6a395d8f5edf8cb0dad2b0ea07b244f82cd38254 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 8 Dec 2022 12:21:36 +0100 Subject: [PATCH 18/19] Update changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4172b6342..167da47d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ # Changelog ## latest -[full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.13.0...develop) +[full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.14.0...develop) + +Nothing here yet + +## v.0.14.0 +[full changelog](https://github.com/JuDFTteam/masci-tools/compare/v0.13.0...v0.14.0) ### Added - Command `masci-tools convert-inpgen` to transform common structure formats, e.g. `cif` into inpgen files. Uses `ase` or `pymatgen` with the corresponding fleur plugins `ase-fleur` and `pymatgen-io-fleur` (install additional dependencies `cmdline-extras`)[[#215]](https://github.com/JuDFTteam/masci-tools/pull/215) From 5958b3d8bdf0ab8c6a7bdf1043b8df351608cfa6 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 8 Dec 2022 12:37:45 +0100 Subject: [PATCH 19/19] fix codecov.yml --- codecov.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index 4efc0bcf4..fde92f45d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -26,5 +26,5 @@ comment: require_changes: no ignore: - - "masci_tools/util/kkr_rms_tracker.py" - - "masci_tools/util/modifypotential.py" + - "masci_tools/tools/kkr_rms_tracker.py" + - "masci_tools/tools/modifypotential.py"