1313from ase .units import Bohr , Ha , _e , _hbar
1414from ipi .engine .simulation import Simulation
1515from ipi .utils .softexit import softexit
16+ from ipi .utils .parsing import read_output
1617
1718from psiflow .geometry import Geometry
1819from psiflow .sampling .utils import create_xml_list
@@ -93,11 +94,34 @@ def wait_for_clients(input_xml, timeout: int = 60) -> None:
9394 raise ConnectionError (msg )
9495
9596
97+ def add_extras (noutputs : int ) -> None :
98+ # property headers
99+ file_props = next (Path .cwd ().glob (f"*0*.properties" )) # properties should be the same for all coupled walkers?
100+ _ , info_dict = read_output (file_props )
101+ props_headers = ["# column {} --> {}{} : {}" .format (i , key , "{" + info_dict [key ][0 ] + "}" , info_dict [key ][1 ]) for i , key in enumerate (info_dict )]
102+ # extras headers
103+ file_extras = next (Path .cwd ().glob (f"*0*.extras*" )) # extras should be the same for all coupled walkers?
104+ assert file_extras is not None , "No extras file found."
105+ with open (file_extras , "r" ) as f :
106+ line = f .readline ()
107+ start = line .find ("(" ) + 1
108+ end = line .find (")" )
109+ extra_names = line [start :end ].split ("," )
110+ extras_headers = ["# column {} --> {}{} : {}" .format (i + len (props_headers ), name , "{au}" , "PLUMED variable" ) for i , name in enumerate (extra_names )]
111+ # add extras values to properties files
112+ for idx in range (noutputs ):
113+ file_props = next (Path .cwd ().glob (f"*{ idx } *.properties" ))
114+ file_extras = next (Path .cwd ().glob (f"*{ idx } *.extras*" ))
115+ np .savetxt (file_props , np .hstack ((np .loadtxt (file_props ), np .loadtxt (file_extras ))), fmt = '%10.8e' , delimiter = ' ' , header = "\n " .join (props_headers ) + "\n " + "\n " .join (extras_headers ), comments = "" )
116+ # granted i-Pi properties file has some weird indentations so the files do not perfectly match
117+ # but output parser still works so who cares
118+
119+
96120def run (start_xyz : str , input_xml : str ):
97121 # prepare starting geometries from context_dir
98122 data_start : list [ase .Atoms ] = read (start_xyz , index = ":" )
99123 for i , at in enumerate (data_start ):
100- print (at .pbc )
124+ print (at .pbc ) # TODO: why print?
101125 if not any (at .pbc ): # set fake large cell for i-PI
102126 at .pbc = True
103127 at .cell = Cell (NONPERIODIC_CELL )
@@ -134,6 +158,14 @@ def cleanup(output_xyz: str, output_props: str, output_trajs: str) -> None:
134158 _write_frames (* states , outputs = [output_xyz ])
135159 print ("Moved checkpoint geometries" )
136160
161+ output_props = _ .split ("," ) if (_ := output_props ) else []
162+ output_trajs = _ .split ("," ) if (_ := output_trajs ) else []
163+
164+ # Add collective variables to simulation properties, if they exist
165+ if output_props :
166+ add_extras (len (output_props ))
167+ print ("Added i-Pi extras output to properties files" )
168+
137169 prefix = ""
138170 if "remd" in content :
139171 # unshuffle simulation output according to ensemble
@@ -144,9 +176,6 @@ def cleanup(output_xyz: str, output_props: str, output_trajs: str) -> None:
144176 assert out .returncode == 0 # TODO: what if it isn't?
145177 print ("REMDSORT" )
146178
147- output_props = _ .split ("," ) if (_ := output_props ) else []
148- output_trajs = _ .split ("," ) if (_ := output_trajs ) else []
149-
150179 # move recorded simulation observables
151180 if len (output_props ):
152181 assert len (states ) == len (output_props )
0 commit comments