diff --git a/docs/pyerrors/input/openQCD.html b/docs/pyerrors/input/openQCD.html index af63fa04..b4568e29 100644 --- a/docs/pyerrors/input/openQCD.html +++ b/docs/pyerrors/input/openQCD.html @@ -144,1145 +144,1179 @@ 48 if files == []: 49 raise Exception("No files found after pattern filter!") 50 - 51 files.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0])) + 51 files = _sort_names(files) 52 return files 53 54 - 55def read_rwms(path, prefix, version='2.0', names=None, **kwargs): - 56 """Read rwms format from given folder structure. Returns a list of length nrw - 57 - 58 Parameters - 59 ---------- - 60 path : str - 61 path that contains the data files - 62 prefix : str - 63 all files in path that start with prefix are considered as input files. - 64 May be used together postfix to consider only special file endings. - 65 Prefix is ignored, if the keyword 'files' is used. - 66 version : str - 67 version of openQCD, default 2.0 - 68 names : list - 69 list of names that is assigned to the data according according - 70 to the order in the file list. Use careful, if you do not provide file names! - 71 r_start : list - 72 list which contains the first config to be read for each replicum - 73 r_stop : list - 74 list which contains the last config to be read for each replicum - 75 r_step : int - 76 integer that defines a fixed step size between two measurements (in units of configs) - 77 If not given, r_step=1 is assumed. - 78 postfix : str - 79 postfix of the file to read, e.g. '.ms1' for openQCD-files - 80 files : list - 81 list which contains the filenames to be read. No automatic detection of - 82 files performed if given. - 83 print_err : bool - 84 Print additional information that is useful for debugging. - 85 - 86 Returns - 87 ------- - 88 rwms : Obs - 89 Reweighting factors read - 90 """ - 91 known_oqcd_versions = ['1.4', '1.6', '2.0'] - 92 if not (version in known_oqcd_versions): - 93 raise Exception('Unknown openQCD version defined!') - 94 print("Working with openQCD version " + version) - 95 if 'postfix' in kwargs: - 96 postfix = kwargs.get('postfix') - 97 else: - 98 postfix = '' - 99 - 100 if 'files' in kwargs: - 101 known_files = kwargs.get('files') - 102 else: - 103 known_files = [] - 104 - 105 ls = _find_files(path, prefix, postfix, 'dat', known_files=known_files) - 106 - 107 replica = len(ls) - 108 - 109 if 'r_start' in kwargs: - 110 r_start = kwargs.get('r_start') - 111 if len(r_start) != replica: - 112 raise Exception('r_start does not match number of replicas') - 113 r_start = [o if o else None for o in r_start] - 114 else: - 115 r_start = [None] * replica - 116 - 117 if 'r_stop' in kwargs: - 118 r_stop = kwargs.get('r_stop') - 119 if len(r_stop) != replica: - 120 raise Exception('r_stop does not match number of replicas') - 121 else: - 122 r_stop = [None] * replica - 123 - 124 if 'r_step' in kwargs: - 125 r_step = kwargs.get('r_step') + 55def _sort_names(ll): + 56 r_pattern = r'r(\d+)' + 57 id_pattern = r'id(\d+)' + 58 + 59 # sort list by id first + 60 if all([re.search(id_pattern, entry) for entry in ll]): + 61 ll.sort(key=lambda x: int(re.findall(id_pattern, x)[0])) + 62 # then by replikum + 63 if all([re.search(r_pattern, entry) for entry in ll]): + 64 ll.sort(key=lambda x: int(re.findall(r_pattern, x)[0])) + 65 # as the rearrangements by one key let the other key untouched, the list is sorted now + 66 + 67 else: + 68 # fallback + 69 sames = '' + 70 if len(ll) > 1: + 71 for i in range(len(ll[0])): + 72 checking = ll[0][i] + 73 for rn in ll[1:]: + 74 is_same = (rn[i] == checking) + 75 if is_same: + 76 sames += checking + 77 else: + 78 break + 79 print(ll[0][len(sames):]) + 80 ll.sort(key=lambda x: int(re.findall(r'\d+', x[len(sames):])[0])) + 81 return ll + 82 + 83 + 84def read_rwms(path, prefix, version='2.0', names=None, **kwargs): + 85 """Read rwms format from given folder structure. Returns a list of length nrw + 86 + 87 Parameters + 88 ---------- + 89 path : str + 90 path that contains the data files + 91 prefix : str + 92 all files in path that start with prefix are considered as input files. + 93 May be used together postfix to consider only special file endings. + 94 Prefix is ignored, if the keyword 'files' is used. + 95 version : str + 96 version of openQCD, default 2.0 + 97 names : list + 98 list of names that is assigned to the data according according + 99 to the order in the file list. Use careful, if you do not provide file names! + 100 r_start : list + 101 list which contains the first config to be read for each replicum + 102 r_stop : list + 103 list which contains the last config to be read for each replicum + 104 r_step : int + 105 integer that defines a fixed step size between two measurements (in units of configs) + 106 If not given, r_step=1 is assumed. + 107 postfix : str + 108 postfix of the file to read, e.g. '.ms1' for openQCD-files + 109 files : list + 110 list which contains the filenames to be read. No automatic detection of + 111 files performed if given. + 112 print_err : bool + 113 Print additional information that is useful for debugging. + 114 + 115 Returns + 116 ------- + 117 rwms : Obs + 118 Reweighting factors read + 119 """ + 120 known_oqcd_versions = ['1.4', '1.6', '2.0'] + 121 if not (version in known_oqcd_versions): + 122 raise Exception('Unknown openQCD version defined!') + 123 print("Working with openQCD version " + version) + 124 if 'postfix' in kwargs: + 125 postfix = kwargs.get('postfix') 126 else: - 127 r_step = 1 + 127 postfix = '' 128 - 129 print('Read reweighting factors from', prefix[:-1], ',', - 130 replica, 'replica', end='') - 131 - 132 if names is None: - 133 rep_names = [] - 134 for entry in ls: - 135 truncated_entry = entry - 136 suffixes = [".dat", ".rwms", ".ms1"] - 137 for suffix in suffixes: - 138 if truncated_entry.endswith(suffix): - 139 truncated_entry = truncated_entry[0:-len(suffix)] - 140 idx = truncated_entry.index('r') - 141 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) - 142 else: - 143 rep_names = names - 144 - 145 print_err = 0 - 146 if 'print_err' in kwargs: - 147 print_err = 1 - 148 print() - 149 - 150 deltas = [] - 151 - 152 configlist = [] - 153 r_start_index = [] - 154 r_stop_index = [] - 155 - 156 for rep in range(replica): - 157 tmp_array = [] - 158 with open(path + '/' + ls[rep], 'rb') as fp: - 159 - 160 t = fp.read(4) # number of reweighting factors - 161 if rep == 0: - 162 nrw = struct.unpack('i', t)[0] - 163 if version == '2.0': - 164 nrw = int(nrw / 2) - 165 for k in range(nrw): - 166 deltas.append([]) - 167 else: - 168 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): - 169 raise Exception('Error: different number of reweighting factors for replicum', rep) - 170 - 171 for k in range(nrw): - 172 tmp_array.append([]) + 129 if 'files' in kwargs: + 130 known_files = kwargs.get('files') + 131 else: + 132 known_files = [] + 133 + 134 ls = _find_files(path, prefix, postfix, 'dat', known_files=known_files) + 135 + 136 replica = len(ls) + 137 + 138 if 'r_start' in kwargs: + 139 r_start = kwargs.get('r_start') + 140 if len(r_start) != replica: + 141 raise Exception('r_start does not match number of replicas') + 142 r_start = [o if o else None for o in r_start] + 143 else: + 144 r_start = [None] * replica + 145 + 146 if 'r_stop' in kwargs: + 147 r_stop = kwargs.get('r_stop') + 148 if len(r_stop) != replica: + 149 raise Exception('r_stop does not match number of replicas') + 150 else: + 151 r_stop = [None] * replica + 152 + 153 if 'r_step' in kwargs: + 154 r_step = kwargs.get('r_step') + 155 else: + 156 r_step = 1 + 157 + 158 print('Read reweighting factors from', prefix[:-1], ',', + 159 replica, 'replica', end='') + 160 + 161 if names is None: + 162 rep_names = [] + 163 for entry in ls: + 164 truncated_entry = entry + 165 suffixes = [".dat", ".rwms", ".ms1"] + 166 for suffix in suffixes: + 167 if truncated_entry.endswith(suffix): + 168 truncated_entry = truncated_entry[0:-len(suffix)] + 169 idx = truncated_entry.index('r') + 170 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) + 171 else: + 172 rep_names = names 173 - 174 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files - 175 nfct = [] - 176 if version in ['1.6', '2.0']: - 177 for i in range(nrw): - 178 t = fp.read(4) - 179 nfct.append(struct.unpack('i', t)[0]) - 180 else: - 181 for i in range(nrw): - 182 nfct.append(1) - 183 - 184 nsrc = [] - 185 for i in range(nrw): - 186 t = fp.read(4) - 187 nsrc.append(struct.unpack('i', t)[0]) - 188 if version == '2.0': - 189 if not struct.unpack('i', fp.read(4))[0] == 0: - 190 raise Exception("You are using the input for openQCD version 2.0, this is not correct.") - 191 - 192 configlist.append([]) - 193 while True: - 194 t = fp.read(4) - 195 if len(t) < 4: - 196 break - 197 config_no = struct.unpack('i', t)[0] - 198 configlist[-1].append(config_no) - 199 for i in range(nrw): - 200 if (version == '2.0'): - 201 tmpd = _read_array_openQCD2(fp) - 202 tmpd = _read_array_openQCD2(fp) - 203 tmp_rw = tmpd['arr'] - 204 tmp_nfct = 1.0 - 205 for j in range(tmpd['n'][0]): - 206 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) - 207 if print_err: - 208 print(config_no, i, j, - 209 np.mean(np.exp(-np.asarray(tmp_rw[j]))), - 210 np.std(np.exp(-np.asarray(tmp_rw[j])))) - 211 print('Sources:', - 212 np.exp(-np.asarray(tmp_rw[j]))) - 213 print('Partial factor:', tmp_nfct) - 214 elif version == '1.6' or version == '1.4': - 215 tmp_nfct = 1.0 - 216 for j in range(nfct[i]): - 217 t = fp.read(8 * nsrc[i]) - 218 t = fp.read(8 * nsrc[i]) - 219 tmp_rw = struct.unpack('d' * nsrc[i], t) - 220 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) - 221 if print_err: - 222 print(config_no, i, j, - 223 np.mean(np.exp(-np.asarray(tmp_rw))), - 224 np.std(np.exp(-np.asarray(tmp_rw)))) - 225 print('Sources:', np.exp(-np.asarray(tmp_rw))) - 226 print('Partial factor:', tmp_nfct) - 227 tmp_array[i].append(tmp_nfct) - 228 - 229 diffmeas = configlist[-1][-1] - configlist[-1][-2] - 230 configlist[-1] = [item // diffmeas for item in configlist[-1]] - 231 if configlist[-1][0] > 1 and diffmeas > 1: - 232 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') - 233 offset = configlist[-1][0] - 1 - 234 configlist[-1] = [item - offset for item in configlist[-1]] - 235 - 236 if r_start[rep] is None: - 237 r_start_index.append(0) - 238 else: - 239 try: - 240 r_start_index.append(configlist[-1].index(r_start[rep])) - 241 except ValueError: - 242 raise Exception('Config %d not in file with range [%d, %d]' % ( - 243 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None - 244 - 245 if r_stop[rep] is None: - 246 r_stop_index.append(len(configlist[-1]) - 1) - 247 else: - 248 try: - 249 r_stop_index.append(configlist[-1].index(r_stop[rep])) - 250 except ValueError: - 251 raise Exception('Config %d not in file with range [%d, %d]' % ( - 252 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None - 253 - 254 for k in range(nrw): - 255 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) - 256 - 257 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): - 258 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) - 259 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] - 260 if np.any([step != 1 for step in stepsizes]): - 261 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) - 262 - 263 print(',', nrw, 'reweighting factors with', nsrc, 'sources') - 264 result = [] - 265 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] + 174 rep_names = _sort_names(rep_names) + 175 + 176 print_err = 0 + 177 if 'print_err' in kwargs: + 178 print_err = 1 + 179 print() + 180 + 181 deltas = [] + 182 + 183 configlist = [] + 184 r_start_index = [] + 185 r_stop_index = [] + 186 + 187 for rep in range(replica): + 188 tmp_array = [] + 189 with open(path + '/' + ls[rep], 'rb') as fp: + 190 + 191 t = fp.read(4) # number of reweighting factors + 192 if rep == 0: + 193 nrw = struct.unpack('i', t)[0] + 194 if version == '2.0': + 195 nrw = int(nrw / 2) + 196 for k in range(nrw): + 197 deltas.append([]) + 198 else: + 199 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): + 200 raise Exception('Error: different number of reweighting factors for replicum', rep) + 201 + 202 for k in range(nrw): + 203 tmp_array.append([]) + 204 + 205 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files + 206 nfct = [] + 207 if version in ['1.6', '2.0']: + 208 for i in range(nrw): + 209 t = fp.read(4) + 210 nfct.append(struct.unpack('i', t)[0]) + 211 else: + 212 for i in range(nrw): + 213 nfct.append(1) + 214 + 215 nsrc = [] + 216 for i in range(nrw): + 217 t = fp.read(4) + 218 nsrc.append(struct.unpack('i', t)[0]) + 219 if version == '2.0': + 220 if not struct.unpack('i', fp.read(4))[0] == 0: + 221 raise Exception("You are using the input for openQCD version 2.0, this is not correct.") + 222 + 223 configlist.append([]) + 224 while True: + 225 t = fp.read(4) + 226 if len(t) < 4: + 227 break + 228 config_no = struct.unpack('i', t)[0] + 229 configlist[-1].append(config_no) + 230 for i in range(nrw): + 231 if (version == '2.0'): + 232 tmpd = _read_array_openQCD2(fp) + 233 tmpd = _read_array_openQCD2(fp) + 234 tmp_rw = tmpd['arr'] + 235 tmp_nfct = 1.0 + 236 for j in range(tmpd['n'][0]): + 237 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) + 238 if print_err: + 239 print(config_no, i, j, + 240 np.mean(np.exp(-np.asarray(tmp_rw[j]))), + 241 np.std(np.exp(-np.asarray(tmp_rw[j])))) + 242 print('Sources:', + 243 np.exp(-np.asarray(tmp_rw[j]))) + 244 print('Partial factor:', tmp_nfct) + 245 elif version == '1.6' or version == '1.4': + 246 tmp_nfct = 1.0 + 247 for j in range(nfct[i]): + 248 t = fp.read(8 * nsrc[i]) + 249 t = fp.read(8 * nsrc[i]) + 250 tmp_rw = struct.unpack('d' * nsrc[i], t) + 251 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) + 252 if print_err: + 253 print(config_no, i, j, + 254 np.mean(np.exp(-np.asarray(tmp_rw))), + 255 np.std(np.exp(-np.asarray(tmp_rw)))) + 256 print('Sources:', np.exp(-np.asarray(tmp_rw))) + 257 print('Partial factor:', tmp_nfct) + 258 tmp_array[i].append(tmp_nfct) + 259 + 260 diffmeas = configlist[-1][-1] - configlist[-1][-2] + 261 configlist[-1] = [item // diffmeas for item in configlist[-1]] + 262 if configlist[-1][0] > 1 and diffmeas > 1: + 263 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') + 264 offset = configlist[-1][0] - 1 + 265 configlist[-1] = [item - offset for item in configlist[-1]] 266 - 267 for t in range(nrw): - 268 result.append(Obs(deltas[t], rep_names, idl=idl)) - 269 return result - 270 - 271 - 272def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): - 273 """Extract t0 from given .ms.dat files. Returns t0 as Obs. - 274 - 275 It is assumed that all boundary effects have - 276 sufficiently decayed at x0=xmin. - 277 The data around the zero crossing of t^2<E> - 0.3 - 278 is fitted with a linear function - 279 from which the exact root is extracted. - 280 - 281 It is assumed that one measurement is performed for each config. - 282 If this is not the case, the resulting idl, as well as the handling - 283 of r_start, r_stop and r_step is wrong and the user has to correct - 284 this in the resulting observable. - 285 - 286 Parameters - 287 ---------- - 288 path : str - 289 Path to .ms.dat files - 290 prefix : str - 291 Ensemble prefix - 292 dtr_read : int - 293 Determines how many trajectories should be skipped - 294 when reading the ms.dat files. - 295 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. - 296 xmin : int - 297 First timeslice where the boundary - 298 effects have sufficiently decayed. - 299 spatial_extent : int - 300 spatial extent of the lattice, required for normalization. - 301 fit_range : int - 302 Number of data points left and right of the zero - 303 crossing to be included in the linear fit. (Default: 5) - 304 r_start : list - 305 list which contains the first config to be read for each replicum. - 306 r_stop : list - 307 list which contains the last config to be read for each replicum. - 308 r_step : int - 309 integer that defines a fixed step size between two measurements (in units of configs) - 310 If not given, r_step=1 is assumed. - 311 plaquette : bool - 312 If true extract the plaquette estimate of t0 instead. - 313 names : list - 314 list of names that is assigned to the data according according - 315 to the order in the file list. Use careful, if you do not provide file names! - 316 files : list - 317 list which contains the filenames to be read. No automatic detection of - 318 files performed if given. - 319 plot_fit : bool - 320 If true, the fit for the extraction of t0 is shown together with the data. - 321 assume_thermalization : bool - 322 If True: If the first record divided by the distance between two measurements is larger than - 323 1, it is assumed that this is due to thermalization and the first measurement belongs - 324 to the first config (default). - 325 If False: The config numbers are assumed to be traj_number // difference - 326 - 327 Returns - 328 ------- - 329 t0 : Obs - 330 Extracted t0 - 331 """ - 332 - 333 if 'files' in kwargs: - 334 known_files = kwargs.get('files') - 335 else: - 336 known_files = [] - 337 - 338 ls = _find_files(path, prefix, 'ms', 'dat', known_files=known_files) - 339 - 340 replica = len(ls) - 341 - 342 if 'r_start' in kwargs: - 343 r_start = kwargs.get('r_start') - 344 if len(r_start) != replica: - 345 raise Exception('r_start does not match number of replicas') - 346 r_start = [o if o else None for o in r_start] - 347 else: - 348 r_start = [None] * replica - 349 - 350 if 'r_stop' in kwargs: - 351 r_stop = kwargs.get('r_stop') - 352 if len(r_stop) != replica: - 353 raise Exception('r_stop does not match number of replicas') - 354 else: - 355 r_stop = [None] * replica - 356 - 357 if 'r_step' in kwargs: - 358 r_step = kwargs.get('r_step') - 359 else: - 360 r_step = 1 - 361 - 362 print('Extract t0 from', prefix, ',', replica, 'replica') + 267 if r_start[rep] is None: + 268 r_start_index.append(0) + 269 else: + 270 try: + 271 r_start_index.append(configlist[-1].index(r_start[rep])) + 272 except ValueError: + 273 raise Exception('Config %d not in file with range [%d, %d]' % ( + 274 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None + 275 + 276 if r_stop[rep] is None: + 277 r_stop_index.append(len(configlist[-1]) - 1) + 278 else: + 279 try: + 280 r_stop_index.append(configlist[-1].index(r_stop[rep])) + 281 except ValueError: + 282 raise Exception('Config %d not in file with range [%d, %d]' % ( + 283 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None + 284 + 285 for k in range(nrw): + 286 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) + 287 + 288 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): + 289 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) + 290 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] + 291 if np.any([step != 1 for step in stepsizes]): + 292 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) + 293 + 294 print(',', nrw, 'reweighting factors with', nsrc, 'sources') + 295 result = [] + 296 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] + 297 + 298 for t in range(nrw): + 299 result.append(Obs(deltas[t], rep_names, idl=idl)) + 300 return result + 301 + 302 + 303def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): + 304 """Extract t0 from given .ms.dat files. Returns t0 as Obs. + 305 + 306 It is assumed that all boundary effects have + 307 sufficiently decayed at x0=xmin. + 308 The data around the zero crossing of t^2<E> - 0.3 + 309 is fitted with a linear function + 310 from which the exact root is extracted. + 311 + 312 It is assumed that one measurement is performed for each config. + 313 If this is not the case, the resulting idl, as well as the handling + 314 of r_start, r_stop and r_step is wrong and the user has to correct + 315 this in the resulting observable. + 316 + 317 Parameters + 318 ---------- + 319 path : str + 320 Path to .ms.dat files + 321 prefix : str + 322 Ensemble prefix + 323 dtr_read : int + 324 Determines how many trajectories should be skipped + 325 when reading the ms.dat files. + 326 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. + 327 xmin : int + 328 First timeslice where the boundary + 329 effects have sufficiently decayed. + 330 spatial_extent : int + 331 spatial extent of the lattice, required for normalization. + 332 fit_range : int + 333 Number of data points left and right of the zero + 334 crossing to be included in the linear fit. (Default: 5) + 335 r_start : list + 336 list which contains the first config to be read for each replicum. + 337 r_stop : list + 338 list which contains the last config to be read for each replicum. + 339 r_step : int + 340 integer that defines a fixed step size between two measurements (in units of configs) + 341 If not given, r_step=1 is assumed. + 342 plaquette : bool + 343 If true extract the plaquette estimate of t0 instead. + 344 names : list + 345 list of names that is assigned to the data according according + 346 to the order in the file list. Use careful, if you do not provide file names! + 347 files : list + 348 list which contains the filenames to be read. No automatic detection of + 349 files performed if given. + 350 plot_fit : bool + 351 If true, the fit for the extraction of t0 is shown together with the data. + 352 assume_thermalization : bool + 353 If True: If the first record divided by the distance between two measurements is larger than + 354 1, it is assumed that this is due to thermalization and the first measurement belongs + 355 to the first config (default). + 356 If False: The config numbers are assumed to be traj_number // difference + 357 + 358 Returns + 359 ------- + 360 t0 : Obs + 361 Extracted t0 + 362 """ 363 - 364 if 'names' in kwargs: - 365 rep_names = kwargs.get('names') + 364 if 'files' in kwargs: + 365 known_files = kwargs.get('files') 366 else: - 367 rep_names = [] - 368 for entry in ls: - 369 truncated_entry = entry.split('.')[0] - 370 idx = truncated_entry.index('r') - 371 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) + 367 known_files = [] + 368 + 369 ls = _find_files(path, prefix, 'ms', 'dat', known_files=known_files) + 370 + 371 replica = len(ls) 372 - 373 Ysum = [] - 374 - 375 configlist = [] - 376 r_start_index = [] - 377 r_stop_index = [] - 378 - 379 for rep in range(replica): + 373 if 'r_start' in kwargs: + 374 r_start = kwargs.get('r_start') + 375 if len(r_start) != replica: + 376 raise Exception('r_start does not match number of replicas') + 377 r_start = [o if o else None for o in r_start] + 378 else: + 379 r_start = [None] * replica 380 - 381 with open(path + '/' + ls[rep], 'rb') as fp: - 382 t = fp.read(12) - 383 header = struct.unpack('iii', t) - 384 if rep == 0: - 385 dn = header[0] - 386 nn = header[1] - 387 tmax = header[2] - 388 elif dn != header[0] or nn != header[1] or tmax != header[2]: - 389 raise Exception('Replica parameters do not match.') - 390 - 391 t = fp.read(8) - 392 if rep == 0: - 393 eps = struct.unpack('d', t)[0] - 394 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) - 395 elif eps != struct.unpack('d', t)[0]: - 396 raise Exception('Values for eps do not match among replica.') - 397 - 398 Ysl = [] - 399 - 400 configlist.append([]) - 401 while True: - 402 t = fp.read(4) - 403 if (len(t) < 4): - 404 break - 405 nc = struct.unpack('i', t)[0] - 406 configlist[-1].append(nc) - 407 - 408 t = fp.read(8 * tmax * (nn + 1)) - 409 if kwargs.get('plaquette'): - 410 if nc % dtr_read == 0: - 411 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) - 412 t = fp.read(8 * tmax * (nn + 1)) - 413 if not kwargs.get('plaquette'): - 414 if nc % dtr_read == 0: - 415 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) - 416 t = fp.read(8 * tmax * (nn + 1)) - 417 - 418 Ysum.append([]) - 419 for i, item in enumerate(Ysl): - 420 Ysum[-1].append([np.mean(item[current + xmin: - 421 current + tmax - xmin]) - 422 for current in range(0, len(item), tmax)]) - 423 - 424 diffmeas = configlist[-1][-1] - configlist[-1][-2] - 425 configlist[-1] = [item // diffmeas for item in configlist[-1]] - 426 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: - 427 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') - 428 offset = configlist[-1][0] - 1 - 429 configlist[-1] = [item - offset for item in configlist[-1]] + 381 if 'r_stop' in kwargs: + 382 r_stop = kwargs.get('r_stop') + 383 if len(r_stop) != replica: + 384 raise Exception('r_stop does not match number of replicas') + 385 else: + 386 r_stop = [None] * replica + 387 + 388 if 'r_step' in kwargs: + 389 r_step = kwargs.get('r_step') + 390 else: + 391 r_step = 1 + 392 + 393 print('Extract t0 from', prefix, ',', replica, 'replica') + 394 + 395 if 'names' in kwargs: + 396 rep_names = kwargs.get('names') + 397 else: + 398 rep_names = [] + 399 for entry in ls: + 400 truncated_entry = entry.split('.')[0] + 401 idx = truncated_entry.index('r') + 402 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) + 403 + 404 Ysum = [] + 405 + 406 configlist = [] + 407 r_start_index = [] + 408 r_stop_index = [] + 409 + 410 for rep in range(replica): + 411 + 412 with open(path + '/' + ls[rep], 'rb') as fp: + 413 t = fp.read(12) + 414 header = struct.unpack('iii', t) + 415 if rep == 0: + 416 dn = header[0] + 417 nn = header[1] + 418 tmax = header[2] + 419 elif dn != header[0] or nn != header[1] or tmax != header[2]: + 420 raise Exception('Replica parameters do not match.') + 421 + 422 t = fp.read(8) + 423 if rep == 0: + 424 eps = struct.unpack('d', t)[0] + 425 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) + 426 elif eps != struct.unpack('d', t)[0]: + 427 raise Exception('Values for eps do not match among replica.') + 428 + 429 Ysl = [] 430 - 431 if r_start[rep] is None: - 432 r_start_index.append(0) - 433 else: - 434 try: - 435 r_start_index.append(configlist[-1].index(r_start[rep])) - 436 except ValueError: - 437 raise Exception('Config %d not in file with range [%d, %d]' % ( - 438 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None - 439 - 440 if r_stop[rep] is None: - 441 r_stop_index.append(len(configlist[-1]) - 1) - 442 else: - 443 try: - 444 r_stop_index.append(configlist[-1].index(r_stop[rep])) - 445 except ValueError: - 446 raise Exception('Config %d not in file with range [%d, %d]' % ( - 447 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None + 431 configlist.append([]) + 432 while True: + 433 t = fp.read(4) + 434 if (len(t) < 4): + 435 break + 436 nc = struct.unpack('i', t)[0] + 437 configlist[-1].append(nc) + 438 + 439 t = fp.read(8 * tmax * (nn + 1)) + 440 if kwargs.get('plaquette'): + 441 if nc % dtr_read == 0: + 442 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) + 443 t = fp.read(8 * tmax * (nn + 1)) + 444 if not kwargs.get('plaquette'): + 445 if nc % dtr_read == 0: + 446 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) + 447 t = fp.read(8 * tmax * (nn + 1)) 448 - 449 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): - 450 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) - 451 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] - 452 if np.any([step != 1 for step in stepsizes]): - 453 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) + 449 Ysum.append([]) + 450 for i, item in enumerate(Ysl): + 451 Ysum[-1].append([np.mean(item[current + xmin: + 452 current + tmax - xmin]) + 453 for current in range(0, len(item), tmax)]) 454 - 455 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] - 456 t2E_dict = {} - 457 for n in range(nn + 1): - 458 samples = [] - 459 for nrep, rep in enumerate(Ysum): - 460 samples.append([]) - 461 for cnfg in rep: - 462 samples[-1].append(cnfg[n]) - 463 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] - 464 new_obs = Obs(samples, rep_names, idl=idl) - 465 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 - 466 - 467 zero_crossing = np.argmax(np.array( - 468 [o.value for o in t2E_dict.values()]) > 0.0) - 469 - 470 x = list(t2E_dict.keys())[zero_crossing - fit_range: - 471 zero_crossing + fit_range] - 472 y = list(t2E_dict.values())[zero_crossing - fit_range: - 473 zero_crossing + fit_range] - 474 [o.gamma_method() for o in y] - 475 - 476 fit_result = fit_lin(x, y) - 477 - 478 if kwargs.get('plot_fit'): - 479 plt.figure() - 480 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) - 481 ax0 = plt.subplot(gs[0]) - 482 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] - 483 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] - 484 [o.gamma_method() for o in ymore] - 485 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') - 486 xplot = np.linspace(np.min(x), np.max(x)) - 487 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] - 488 [yi.gamma_method() for yi in yplot] - 489 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) - 490 retval = (-fit_result[0] / fit_result[1]) - 491 retval.gamma_method() - 492 ylim = ax0.get_ylim() - 493 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) - 494 ax0.set_ylim(ylim) - 495 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') - 496 xlim = ax0.get_xlim() + 455 diffmeas = configlist[-1][-1] - configlist[-1][-2] + 456 configlist[-1] = [item // diffmeas for item in configlist[-1]] + 457 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: + 458 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') + 459 offset = configlist[-1][0] - 1 + 460 configlist[-1] = [item - offset for item in configlist[-1]] + 461 + 462 if r_start[rep] is None: + 463 r_start_index.append(0) + 464 else: + 465 try: + 466 r_start_index.append(configlist[-1].index(r_start[rep])) + 467 except ValueError: + 468 raise Exception('Config %d not in file with range [%d, %d]' % ( + 469 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None + 470 + 471 if r_stop[rep] is None: + 472 r_stop_index.append(len(configlist[-1]) - 1) + 473 else: + 474 try: + 475 r_stop_index.append(configlist[-1].index(r_stop[rep])) + 476 except ValueError: + 477 raise Exception('Config %d not in file with range [%d, %d]' % ( + 478 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None + 479 + 480 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): + 481 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) + 482 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] + 483 if np.any([step != 1 for step in stepsizes]): + 484 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) + 485 + 486 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] + 487 t2E_dict = {} + 488 for n in range(nn + 1): + 489 samples = [] + 490 for nrep, rep in enumerate(Ysum): + 491 samples.append([]) + 492 for cnfg in rep: + 493 samples[-1].append(cnfg[n]) + 494 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] + 495 new_obs = Obs(samples, rep_names, idl=idl) + 496 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 497 - 498 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] - 499 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) - 500 ax1 = plt.subplot(gs[1]) - 501 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) - 502 ax1.tick_params(direction='out') - 503 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) - 504 ax1.axhline(y=0.0, ls='--', color='k') - 505 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') - 506 ax1.set_xlim(xlim) - 507 ax1.set_ylabel('Residuals') - 508 ax1.set_xlabel(r'$t/a^2$') - 509 - 510 plt.draw() - 511 return -fit_result[0] / fit_result[1] - 512 - 513 - 514def _parse_array_openQCD2(d, n, size, wa, quadrupel=False): - 515 arr = [] - 516 if d == 2: - 517 for i in range(n[0]): - 518 tmp = wa[i * n[1]:(i + 1) * n[1]] - 519 if quadrupel: - 520 tmp2 = [] - 521 for j in range(0, len(tmp), 2): - 522 tmp2.append(tmp[j]) - 523 arr.append(tmp2) - 524 else: - 525 arr.append(np.asarray(tmp)) - 526 - 527 else: - 528 raise Exception('Only two-dimensional arrays supported!') - 529 - 530 return arr - 531 - 532 - 533def _read_array_openQCD2(fp): - 534 t = fp.read(4) - 535 d = struct.unpack('i', t)[0] - 536 t = fp.read(4 * d) - 537 n = struct.unpack('%di' % (d), t) - 538 t = fp.read(4) - 539 size = struct.unpack('i', t)[0] - 540 if size == 4: - 541 types = 'i' - 542 elif size == 8: - 543 types = 'd' - 544 elif size == 16: - 545 types = 'dd' - 546 else: - 547 raise Exception("Type for size '" + str(size) + "' not known.") - 548 m = n[0] - 549 for i in range(1, d): - 550 m *= n[i] - 551 - 552 t = fp.read(m * size) - 553 tmp = struct.unpack('%d%s' % (m, types), t) - 554 - 555 arr = _parse_array_openQCD2(d, n, size, tmp, quadrupel=True) - 556 return {'d': d, 'n': n, 'size': size, 'arr': arr} + 498 zero_crossing = np.argmax(np.array( + 499 [o.value for o in t2E_dict.values()]) > 0.0) + 500 + 501 x = list(t2E_dict.keys())[zero_crossing - fit_range: + 502 zero_crossing + fit_range] + 503 y = list(t2E_dict.values())[zero_crossing - fit_range: + 504 zero_crossing + fit_range] + 505 [o.gamma_method() for o in y] + 506 + 507 fit_result = fit_lin(x, y) + 508 + 509 if kwargs.get('plot_fit'): + 510 plt.figure() + 511 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) + 512 ax0 = plt.subplot(gs[0]) + 513 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] + 514 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] + 515 [o.gamma_method() for o in ymore] + 516 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') + 517 xplot = np.linspace(np.min(x), np.max(x)) + 518 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] + 519 [yi.gamma_method() for yi in yplot] + 520 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) + 521 retval = (-fit_result[0] / fit_result[1]) + 522 retval.gamma_method() + 523 ylim = ax0.get_ylim() + 524 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) + 525 ax0.set_ylim(ylim) + 526 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') + 527 xlim = ax0.get_xlim() + 528 + 529 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] + 530 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) + 531 ax1 = plt.subplot(gs[1]) + 532 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) + 533 ax1.tick_params(direction='out') + 534 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) + 535 ax1.axhline(y=0.0, ls='--', color='k') + 536 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') + 537 ax1.set_xlim(xlim) + 538 ax1.set_ylabel('Residuals') + 539 ax1.set_xlabel(r'$t/a^2$') + 540 + 541 plt.draw() + 542 return -fit_result[0] / fit_result[1] + 543 + 544 + 545def _parse_array_openQCD2(d, n, size, wa, quadrupel=False): + 546 arr = [] + 547 if d == 2: + 548 for i in range(n[0]): + 549 tmp = wa[i * n[1]:(i + 1) * n[1]] + 550 if quadrupel: + 551 tmp2 = [] + 552 for j in range(0, len(tmp), 2): + 553 tmp2.append(tmp[j]) + 554 arr.append(tmp2) + 555 else: + 556 arr.append(np.asarray(tmp)) 557 - 558 - 559def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): - 560 """Read the topologial charge based on openQCD gradient flow measurements. - 561 - 562 Parameters - 563 ---------- - 564 path : str - 565 path of the measurement files - 566 prefix : str - 567 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. - 568 Ignored if file names are passed explicitly via keyword files. - 569 c : double - 570 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. - 571 dtr_cnfg : int - 572 (optional) parameter that specifies the number of measurements - 573 between two configs. - 574 If it is not set, the distance between two measurements - 575 in the file is assumed to be the distance between two configurations. - 576 steps : int - 577 (optional) Distance between two configurations in units of trajectories / - 578 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given - 579 version : str - 580 Either openQCD or sfqcd, depending on the data. - 581 L : int - 582 spatial length of the lattice in L/a. - 583 HAS to be set if version != sfqcd, since openQCD does not provide - 584 this in the header - 585 r_start : list - 586 list which contains the first config to be read for each replicum. - 587 r_stop : list - 588 list which contains the last config to be read for each replicum. - 589 files : list - 590 specify the exact files that need to be read - 591 from path, practical if e.g. only one replicum is needed - 592 postfix : str - 593 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files - 594 names : list - 595 Alternative labeling for replicas/ensembles. - 596 Has to have the appropriate length. - 597 Zeuthen_flow : bool - 598 (optional) If True, the Zeuthen flow is used for Qtop. Only possible - 599 for version=='sfqcd' If False, the Wilson flow is used. - 600 integer_charge : bool - 601 If True, the charge is rounded towards the nearest integer on each config. - 602 - 603 Returns - 604 ------- - 605 result : Obs - 606 Read topological charge - 607 """ - 608 - 609 return _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version=version, obspos=0, **kwargs) - 610 - 611 - 612def read_gf_coupling(path, prefix, c, dtr_cnfg=1, Zeuthen_flow=True, **kwargs): - 613 """Read the gradient flow coupling based on sfqcd gradient flow measurements. See 1607.06423 for details. - 614 - 615 Note: The current implementation only works for c=0.3 and T=L. The definition of the coupling in 1607.06423 requires projection to topological charge zero which is not done within this function but has to be performed in a separate step. - 616 - 617 Parameters - 618 ---------- - 619 path : str - 620 path of the measurement files - 621 prefix : str - 622 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. - 623 Ignored if file names are passed explicitly via keyword files. - 624 c : double - 625 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. - 626 dtr_cnfg : int - 627 (optional) parameter that specifies the number of measurements - 628 between two configs. - 629 If it is not set, the distance between two measurements - 630 in the file is assumed to be the distance between two configurations. - 631 steps : int - 632 (optional) Distance between two configurations in units of trajectories / - 633 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given - 634 r_start : list - 635 list which contains the first config to be read for each replicum. - 636 r_stop : list - 637 list which contains the last config to be read for each replicum. - 638 files : list - 639 specify the exact files that need to be read - 640 from path, practical if e.g. only one replicum is needed - 641 names : list - 642 Alternative labeling for replicas/ensembles. - 643 Has to have the appropriate length. - 644 postfix : str - 645 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files - 646 Zeuthen_flow : bool - 647 (optional) If True, the Zeuthen flow is used for the coupling. If False, the Wilson flow is used. - 648 """ - 649 - 650 if c != 0.3: - 651 raise Exception("The required lattice norm is only implemented for c=0.3 at the moment.") - 652 - 653 plaq = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=6, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) - 654 C2x1 = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=7, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) - 655 L = plaq.tag["L"] - 656 T = plaq.tag["T"] - 657 - 658 if T != L: - 659 raise Exception("The required lattice norm is only implemented for T=L at the moment.") - 660 - 661 if Zeuthen_flow is not True: - 662 raise Exception("The required lattice norm is only implemented for the Zeuthen flow at the moment.") - 663 - 664 t = (c * L) ** 2 / 8 - 665 - 666 normdict = {4: 0.012341170468270, - 667 6: 0.010162691462430, - 668 8: 0.009031614807931, - 669 10: 0.008744966371393, - 670 12: 0.008650917856809, - 671 14: 8.611154391267955E-03, - 672 16: 0.008591758449508, - 673 20: 0.008575359627103, - 674 24: 0.008569387847540, - 675 28: 8.566803713382559E-03, - 676 32: 0.008565541650006, - 677 40: 8.564480684962046E-03, - 678 48: 8.564098025073460E-03, - 679 64: 8.563853943383087E-03} + 558 else: + 559 raise Exception('Only two-dimensional arrays supported!') + 560 + 561 return arr + 562 + 563 + 564def _read_array_openQCD2(fp): + 565 t = fp.read(4) + 566 d = struct.unpack('i', t)[0] + 567 t = fp.read(4 * d) + 568 n = struct.unpack('%di' % (d), t) + 569 t = fp.read(4) + 570 size = struct.unpack('i', t)[0] + 571 if size == 4: + 572 types = 'i' + 573 elif size == 8: + 574 types = 'd' + 575 elif size == 16: + 576 types = 'dd' + 577 else: + 578 raise Exception("Type for size '" + str(size) + "' not known.") + 579 m = n[0] + 580 for i in range(1, d): + 581 m *= n[i] + 582 + 583 t = fp.read(m * size) + 584 tmp = struct.unpack('%d%s' % (m, types), t) + 585 + 586 arr = _parse_array_openQCD2(d, n, size, tmp, quadrupel=True) + 587 return {'d': d, 'n': n, 'size': size, 'arr': arr} + 588 + 589 + 590def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): + 591 """Read the topologial charge based on openQCD gradient flow measurements. + 592 + 593 Parameters + 594 ---------- + 595 path : str + 596 path of the measurement files + 597 prefix : str + 598 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. + 599 Ignored if file names are passed explicitly via keyword files. + 600 c : double + 601 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. + 602 dtr_cnfg : int + 603 (optional) parameter that specifies the number of measurements + 604 between two configs. + 605 If it is not set, the distance between two measurements + 606 in the file is assumed to be the distance between two configurations. + 607 steps : int + 608 (optional) Distance between two configurations in units of trajectories / + 609 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given + 610 version : str + 611 Either openQCD or sfqcd, depending on the data. + 612 L : int + 613 spatial length of the lattice in L/a. + 614 HAS to be set if version != sfqcd, since openQCD does not provide + 615 this in the header + 616 r_start : list + 617 list which contains the first config to be read for each replicum. + 618 r_stop : list + 619 list which contains the last config to be read for each replicum. + 620 files : list + 621 specify the exact files that need to be read + 622 from path, practical if e.g. only one replicum is needed + 623 postfix : str + 624 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files + 625 names : list + 626 Alternative labeling for replicas/ensembles. + 627 Has to have the appropriate length. + 628 Zeuthen_flow : bool + 629 (optional) If True, the Zeuthen flow is used for Qtop. Only possible + 630 for version=='sfqcd' If False, the Wilson flow is used. + 631 integer_charge : bool + 632 If True, the charge is rounded towards the nearest integer on each config. + 633 + 634 Returns + 635 ------- + 636 result : Obs + 637 Read topological charge + 638 """ + 639 + 640 return _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version=version, obspos=0, **kwargs) + 641 + 642 + 643def read_gf_coupling(path, prefix, c, dtr_cnfg=1, Zeuthen_flow=True, **kwargs): + 644 """Read the gradient flow coupling based on sfqcd gradient flow measurements. See 1607.06423 for details. + 645 + 646 Note: The current implementation only works for c=0.3 and T=L. The definition of the coupling in 1607.06423 requires projection to topological charge zero which is not done within this function but has to be performed in a separate step. + 647 + 648 Parameters + 649 ---------- + 650 path : str + 651 path of the measurement files + 652 prefix : str + 653 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. + 654 Ignored if file names are passed explicitly via keyword files. + 655 c : double + 656 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. + 657 dtr_cnfg : int + 658 (optional) parameter that specifies the number of measurements + 659 between two configs. + 660 If it is not set, the distance between two measurements + 661 in the file is assumed to be the distance between two configurations. + 662 steps : int + 663 (optional) Distance between two configurations in units of trajectories / + 664 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given + 665 r_start : list + 666 list which contains the first config to be read for each replicum. + 667 r_stop : list + 668 list which contains the last config to be read for each replicum. + 669 files : list + 670 specify the exact files that need to be read + 671 from path, practical if e.g. only one replicum is needed + 672 names : list + 673 Alternative labeling for replicas/ensembles. + 674 Has to have the appropriate length. + 675 postfix : str + 676 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files + 677 Zeuthen_flow : bool + 678 (optional) If True, the Zeuthen flow is used for the coupling. If False, the Wilson flow is used. + 679 """ 680 - 681 return t * t * (5 / 3 * plaq - 1 / 12 * C2x1) / normdict[L] - 682 + 681 if c != 0.3: + 682 raise Exception("The required lattice norm is only implemented for c=0.3 at the moment.") 683 - 684def _read_flow_obs(path, prefix, c, dtr_cnfg=1, version="openQCD", obspos=0, sum_t=True, **kwargs): - 685 """Read a flow observable based on openQCD gradient flow measurements. - 686 - 687 Parameters - 688 ---------- - 689 path : str - 690 path of the measurement files - 691 prefix : str - 692 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. - 693 Ignored if file names are passed explicitly via keyword files. - 694 c : double - 695 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. - 696 dtr_cnfg : int - 697 (optional) parameter that specifies the number of measurements - 698 between two configs. - 699 If it is not set, the distance between two measurements - 700 in the file is assumed to be the distance between two configurations. - 701 steps : int - 702 (optional) Distance between two configurations in units of trajectories / - 703 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given - 704 version : str - 705 Either openQCD or sfqcd, depending on the data. - 706 obspos : int - 707 position of the obeservable in the measurement file. Only relevant for sfqcd files. - 708 sum_t : bool - 709 If true sum over all timeslices, if false only take the value at T/2. - 710 L : int - 711 spatial length of the lattice in L/a. - 712 HAS to be set if version != sfqcd, since openQCD does not provide - 713 this in the header - 714 r_start : list - 715 list which contains the first config to be read for each replicum. - 716 r_stop : list - 717 list which contains the last config to be read for each replicum. - 718 files : list - 719 specify the exact files that need to be read - 720 from path, practical if e.g. only one replicum is needed - 721 names : list - 722 Alternative labeling for replicas/ensembles. - 723 Has to have the appropriate length. - 724 postfix : str - 725 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files - 726 Zeuthen_flow : bool - 727 (optional) If True, the Zeuthen flow is used for Qtop. Only possible - 728 for version=='sfqcd' If False, the Wilson flow is used. - 729 integer_charge : bool - 730 If True, the charge is rounded towards the nearest integer on each config. - 731 - 732 Returns - 733 ------- - 734 result : Obs - 735 flow observable specified - 736 """ - 737 known_versions = ["openQCD", "sfqcd"] - 738 - 739 if version not in known_versions: - 740 raise Exception("Unknown openQCD version.") - 741 if "steps" in kwargs: - 742 steps = kwargs.get("steps") - 743 if version == "sfqcd": - 744 if "L" in kwargs: - 745 supposed_L = kwargs.get("L") - 746 else: - 747 supposed_L = None - 748 postfix = "gfms" - 749 else: - 750 if "L" not in kwargs: - 751 raise Exception("This version of openQCD needs you to provide the spatial length of the lattice as parameter 'L'.") - 752 else: - 753 L = kwargs.get("L") - 754 postfix = "ms" - 755 - 756 if "postfix" in kwargs: - 757 postfix = kwargs.get("postfix") - 758 - 759 if "files" in kwargs: - 760 known_files = kwargs.get("files") - 761 else: - 762 known_files = [] - 763 - 764 files = _find_files(path, prefix, postfix, "dat", known_files=known_files) - 765 - 766 if 'r_start' in kwargs: - 767 r_start = kwargs.get('r_start') - 768 if len(r_start) != len(files): - 769 raise Exception('r_start does not match number of replicas') - 770 r_start = [o if o else None for o in r_start] - 771 else: - 772 r_start = [None] * len(files) - 773 - 774 if 'r_stop' in kwargs: - 775 r_stop = kwargs.get('r_stop') - 776 if len(r_stop) != len(files): - 777 raise Exception('r_stop does not match number of replicas') - 778 else: - 779 r_stop = [None] * len(files) - 780 rep_names = [] - 781 - 782 zeuthen = kwargs.get('Zeuthen_flow', False) - 783 if zeuthen and version not in ['sfqcd']: - 784 raise Exception('Zeuthen flow can only be used for version==sfqcd') - 785 - 786 r_start_index = [] - 787 r_stop_index = [] - 788 deltas = [] - 789 configlist = [] - 790 if not zeuthen: - 791 obspos += 8 - 792 for rep, file in enumerate(files): - 793 with open(path + "/" + file, "rb") as fp: + 684 plaq = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=6, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) + 685 C2x1 = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=7, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) + 686 L = plaq.tag["L"] + 687 T = plaq.tag["T"] + 688 + 689 if T != L: + 690 raise Exception("The required lattice norm is only implemented for T=L at the moment.") + 691 + 692 if Zeuthen_flow is not True: + 693 raise Exception("The required lattice norm is only implemented for the Zeuthen flow at the moment.") + 694 + 695 t = (c * L) ** 2 / 8 + 696 + 697 normdict = {4: 0.012341170468270, + 698 6: 0.010162691462430, + 699 8: 0.009031614807931, + 700 10: 0.008744966371393, + 701 12: 0.008650917856809, + 702 14: 8.611154391267955E-03, + 703 16: 0.008591758449508, + 704 20: 0.008575359627103, + 705 24: 0.008569387847540, + 706 28: 8.566803713382559E-03, + 707 32: 0.008565541650006, + 708 40: 8.564480684962046E-03, + 709 48: 8.564098025073460E-03, + 710 64: 8.563853943383087E-03} + 711 + 712 return t * t * (5 / 3 * plaq - 1 / 12 * C2x1) / normdict[L] + 713 + 714 + 715def _read_flow_obs(path, prefix, c, dtr_cnfg=1, version="openQCD", obspos=0, sum_t=True, **kwargs): + 716 """Read a flow observable based on openQCD gradient flow measurements. + 717 + 718 Parameters + 719 ---------- + 720 path : str + 721 path of the measurement files + 722 prefix : str + 723 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. + 724 Ignored if file names are passed explicitly via keyword files. + 725 c : double + 726 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. + 727 dtr_cnfg : int + 728 (optional) parameter that specifies the number of measurements + 729 between two configs. + 730 If it is not set, the distance between two measurements + 731 in the file is assumed to be the distance between two configurations. + 732 steps : int + 733 (optional) Distance between two configurations in units of trajectories / + 734 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given + 735 version : str + 736 Either openQCD or sfqcd, depending on the data. + 737 obspos : int + 738 position of the obeservable in the measurement file. Only relevant for sfqcd files. + 739 sum_t : bool + 740 If true sum over all timeslices, if false only take the value at T/2. + 741 L : int + 742 spatial length of the lattice in L/a. + 743 HAS to be set if version != sfqcd, since openQCD does not provide + 744 this in the header + 745 r_start : list + 746 list which contains the first config to be read for each replicum. + 747 r_stop : list + 748 list which contains the last config to be read for each replicum. + 749 files : list + 750 specify the exact files that need to be read + 751 from path, practical if e.g. only one replicum is needed + 752 names : list + 753 Alternative labeling for replicas/ensembles. + 754 Has to have the appropriate length. + 755 postfix : str + 756 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files + 757 Zeuthen_flow : bool + 758 (optional) If True, the Zeuthen flow is used for Qtop. Only possible + 759 for version=='sfqcd' If False, the Wilson flow is used. + 760 integer_charge : bool + 761 If True, the charge is rounded towards the nearest integer on each config. + 762 + 763 Returns + 764 ------- + 765 result : Obs + 766 flow observable specified + 767 """ + 768 known_versions = ["openQCD", "sfqcd"] + 769 + 770 if version not in known_versions: + 771 raise Exception("Unknown openQCD version.") + 772 if "steps" in kwargs: + 773 steps = kwargs.get("steps") + 774 if version == "sfqcd": + 775 if "L" in kwargs: + 776 supposed_L = kwargs.get("L") + 777 else: + 778 supposed_L = None + 779 postfix = "gfms" + 780 else: + 781 if "L" not in kwargs: + 782 raise Exception("This version of openQCD needs you to provide the spatial length of the lattice as parameter 'L'.") + 783 else: + 784 L = kwargs.get("L") + 785 postfix = "ms" + 786 + 787 if "postfix" in kwargs: + 788 postfix = kwargs.get("postfix") + 789 + 790 if "files" in kwargs: + 791 known_files = kwargs.get("files") + 792 else: + 793 known_files = [] 794 - 795 Q = [] - 796 traj_list = [] - 797 if version in ['sfqcd']: - 798 t = fp.read(12) - 799 header = struct.unpack('<iii', t) - 800 zthfl = header[0] # Zeuthen flow -> if it's equal to 2 it means that the Zeuthen flow is also 'measured' (apart from the Wilson flow) - 801 ncs = header[1] # number of different values for c in t_flow=1/8 c² L² -> measurements done for ncs c's - 802 tmax = header[2] # lattice T/a - 803 - 804 t = fp.read(12) - 805 Ls = struct.unpack('<iii', t) - 806 if (Ls[0] == Ls[1] and Ls[1] == Ls[2]): - 807 L = Ls[0] - 808 if not (supposed_L == L) and supposed_L: - 809 raise Exception("It seems the length given in the header and by you contradict each other") - 810 else: - 811 raise Exception("Found more than one spatial length in header!") + 795 files = _find_files(path, prefix, postfix, "dat", known_files=known_files) + 796 + 797 if 'r_start' in kwargs: + 798 r_start = kwargs.get('r_start') + 799 if len(r_start) != len(files): + 800 raise Exception('r_start does not match number of replicas') + 801 r_start = [o if o else None for o in r_start] + 802 else: + 803 r_start = [None] * len(files) + 804 + 805 if 'r_stop' in kwargs: + 806 r_stop = kwargs.get('r_stop') + 807 if len(r_stop) != len(files): + 808 raise Exception('r_stop does not match number of replicas') + 809 else: + 810 r_stop = [None] * len(files) + 811 rep_names = [] 812 - 813 t = fp.read(16) - 814 header2 = struct.unpack('<dd', t) - 815 tol = header2[0] - 816 cmax = header2[1] # highest value of c used - 817 - 818 if c > cmax: - 819 raise Exception('Flow has been determined between c=0 and c=%lf with tolerance %lf' % (cmax, tol)) - 820 - 821 if (zthfl == 2): - 822 nfl = 2 # number of flows - 823 else: - 824 nfl = 1 - 825 iobs = 8 * nfl # number of flow observables calculated - 826 - 827 while True: - 828 t = fp.read(4) - 829 if (len(t) < 4): - 830 break - 831 traj_list.append(struct.unpack('i', t)[0]) # trajectory number when measurement was done - 832 - 833 for j in range(ncs + 1): - 834 for i in range(iobs): - 835 t = fp.read(8 * tmax) - 836 if (i == obspos): # determines the flow observable -> i=0 <-> Zeuthen flow - 837 Q.append(struct.unpack('d' * tmax, t)) - 838 - 839 else: - 840 t = fp.read(12) - 841 header = struct.unpack('<iii', t) - 842 # step size in integration steps "dnms" - 843 dn = header[0] - 844 # number of measurements, so "ntot"/dn - 845 nn = header[1] - 846 # lattice T/a - 847 tmax = header[2] + 813 zeuthen = kwargs.get('Zeuthen_flow', False) + 814 if zeuthen and version not in ['sfqcd']: + 815 raise Exception('Zeuthen flow can only be used for version==sfqcd') + 816 + 817 r_start_index = [] + 818 r_stop_index = [] + 819 deltas = [] + 820 configlist = [] + 821 if not zeuthen: + 822 obspos += 8 + 823 for rep, file in enumerate(files): + 824 with open(path + "/" + file, "rb") as fp: + 825 + 826 Q = [] + 827 traj_list = [] + 828 if version in ['sfqcd']: + 829 t = fp.read(12) + 830 header = struct.unpack('<iii', t) + 831 zthfl = header[0] # Zeuthen flow -> if it's equal to 2 it means that the Zeuthen flow is also 'measured' (apart from the Wilson flow) + 832 ncs = header[1] # number of different values for c in t_flow=1/8 c² L² -> measurements done for ncs c's + 833 tmax = header[2] # lattice T/a + 834 + 835 t = fp.read(12) + 836 Ls = struct.unpack('<iii', t) + 837 if (Ls[0] == Ls[1] and Ls[1] == Ls[2]): + 838 L = Ls[0] + 839 if not (supposed_L == L) and supposed_L: + 840 raise Exception("It seems the length given in the header and by you contradict each other") + 841 else: + 842 raise Exception("Found more than one spatial length in header!") + 843 + 844 t = fp.read(16) + 845 header2 = struct.unpack('<dd', t) + 846 tol = header2[0] + 847 cmax = header2[1] # highest value of c used 848 - 849 t = fp.read(8) - 850 eps = struct.unpack('d', t)[0] + 849 if c > cmax: + 850 raise Exception('Flow has been determined between c=0 and c=%lf with tolerance %lf' % (cmax, tol)) 851 - 852 while True: - 853 t = fp.read(4) - 854 if (len(t) < 4): - 855 break - 856 traj_list.append(struct.unpack('i', t)[0]) - 857 # Wsl - 858 t = fp.read(8 * tmax * (nn + 1)) - 859 # Ysl - 860 t = fp.read(8 * tmax * (nn + 1)) - 861 # Qsl, which is asked for in this method - 862 t = fp.read(8 * tmax * (nn + 1)) - 863 # unpack the array of Qtops, - 864 # on each timeslice t=0,...,tmax-1 and the - 865 # measurement number in = 0...nn (see README.qcd1) - 866 tmpd = struct.unpack('d' * tmax * (nn + 1), t) - 867 Q.append(tmpd) - 868 - 869 if len(np.unique(np.diff(traj_list))) != 1: - 870 raise Exception("Irregularities in stepsize found") - 871 else: - 872 if 'steps' in kwargs: - 873 if steps != traj_list[1] - traj_list[0]: - 874 raise Exception("steps and the found stepsize are not the same") - 875 else: - 876 steps = traj_list[1] - traj_list[0] - 877 - 878 configlist.append([tr // steps // dtr_cnfg for tr in traj_list]) - 879 if configlist[-1][0] > 1: - 880 offset = configlist[-1][0] - 1 - 881 warnings.warn('Assume thermalization and that the first measurement belongs to the first config. Offset = %d configs (%d trajectories / cycles)' % ( - 882 offset, offset * steps)) - 883 configlist[-1] = [item - offset for item in configlist[-1]] - 884 - 885 if r_start[rep] is None: - 886 r_start_index.append(0) - 887 else: - 888 try: - 889 r_start_index.append(configlist[-1].index(r_start[rep])) - 890 except ValueError: - 891 raise Exception('Config %d not in file with range [%d, %d]' % ( - 892 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None - 893 - 894 if r_stop[rep] is None: - 895 r_stop_index.append(len(configlist[-1]) - 1) - 896 else: - 897 try: - 898 r_stop_index.append(configlist[-1].index(r_stop[rep])) - 899 except ValueError: - 900 raise Exception('Config %d not in file with range [%d, %d]' % ( - 901 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None - 902 - 903 if version in ['sfqcd']: - 904 cstepsize = cmax / ncs - 905 index_aim = round(c / cstepsize) - 906 else: - 907 t_aim = (c * L) ** 2 / 8 - 908 index_aim = round(t_aim / eps / dn) - 909 - 910 Q_sum = [] - 911 for i, item in enumerate(Q): - 912 if sum_t is True: - 913 Q_sum.append([sum(item[current:current + tmax]) - 914 for current in range(0, len(item), tmax)]) - 915 else: - 916 Q_sum.append([item[int(tmax / 2)]]) - 917 Q_top = [] - 918 if version in ['sfqcd']: - 919 for i in range(len(Q_sum) // (ncs + 1)): - 920 Q_top.append(Q_sum[i * (ncs + 1) + index_aim][0]) - 921 else: - 922 for i in range(len(Q) // dtr_cnfg): - 923 Q_top.append(Q_sum[dtr_cnfg * i][index_aim]) - 924 if len(Q_top) != len(traj_list) // dtr_cnfg: - 925 raise Exception("qtops and traj_list dont have the same length") - 926 - 927 if kwargs.get('integer_charge', False): - 928 Q_top = [round(q) for q in Q_top] - 929 - 930 truncated_file = file[:-len(postfix)] - 931 - 932 if "names" not in kwargs: - 933 try: - 934 idx = truncated_file.index('r') - 935 except Exception: - 936 if "names" not in kwargs: - 937 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") - 938 ens_name = truncated_file[:idx] - 939 rep_names.append(ens_name + '|' + truncated_file[idx:]) - 940 else: - 941 names = kwargs.get("names") - 942 rep_names = names - 943 deltas.append(Q_top) - 944 - 945 idl = [range(int(configlist[rep][r_start_index[rep]]), int(configlist[rep][r_stop_index[rep]]) + 1, 1) for rep in range(len(deltas))] - 946 deltas = [deltas[nrep][r_start_index[nrep]:r_stop_index[nrep] + 1] for nrep in range(len(deltas))] - 947 result = Obs(deltas, rep_names, idl=idl) - 948 result.tag = {"T": tmax - 1, - 949 "L": L} - 950 return result - 951 - 952 - 953def qtop_projection(qtop, target=0): - 954 """Returns the projection to the topological charge sector defined by target. - 955 - 956 Parameters - 957 ---------- - 958 path : Obs - 959 Topological charge. - 960 target : int - 961 Specifies the topological sector to be reweighted to (default 0) + 852 if (zthfl == 2): + 853 nfl = 2 # number of flows + 854 else: + 855 nfl = 1 + 856 iobs = 8 * nfl # number of flow observables calculated + 857 + 858 while True: + 859 t = fp.read(4) + 860 if (len(t) < 4): + 861 break + 862 traj_list.append(struct.unpack('i', t)[0]) # trajectory number when measurement was done + 863 + 864 for j in range(ncs + 1): + 865 for i in range(iobs): + 866 t = fp.read(8 * tmax) + 867 if (i == obspos): # determines the flow observable -> i=0 <-> Zeuthen flow + 868 Q.append(struct.unpack('d' * tmax, t)) + 869 + 870 else: + 871 t = fp.read(12) + 872 header = struct.unpack('<iii', t) + 873 # step size in integration steps "dnms" + 874 dn = header[0] + 875 # number of measurements, so "ntot"/dn + 876 nn = header[1] + 877 # lattice T/a + 878 tmax = header[2] + 879 + 880 t = fp.read(8) + 881 eps = struct.unpack('d', t)[0] + 882 + 883 while True: + 884 t = fp.read(4) + 885 if (len(t) < 4): + 886 break + 887 traj_list.append(struct.unpack('i', t)[0]) + 888 # Wsl + 889 t = fp.read(8 * tmax * (nn + 1)) + 890 # Ysl + 891 t = fp.read(8 * tmax * (nn + 1)) + 892 # Qsl, which is asked for in this method + 893 t = fp.read(8 * tmax * (nn + 1)) + 894 # unpack the array of Qtops, + 895 # on each timeslice t=0,...,tmax-1 and the + 896 # measurement number in = 0...nn (see README.qcd1) + 897 tmpd = struct.unpack('d' * tmax * (nn + 1), t) + 898 Q.append(tmpd) + 899 + 900 if len(np.unique(np.diff(traj_list))) != 1: + 901 raise Exception("Irregularities in stepsize found") + 902 else: + 903 if 'steps' in kwargs: + 904 if steps != traj_list[1] - traj_list[0]: + 905 raise Exception("steps and the found stepsize are not the same") + 906 else: + 907 steps = traj_list[1] - traj_list[0] + 908 + 909 configlist.append([tr // steps // dtr_cnfg for tr in traj_list]) + 910 if configlist[-1][0] > 1: + 911 offset = configlist[-1][0] - 1 + 912 warnings.warn('Assume thermalization and that the first measurement belongs to the first config. Offset = %d configs (%d trajectories / cycles)' % ( + 913 offset, offset * steps)) + 914 configlist[-1] = [item - offset for item in configlist[-1]] + 915 + 916 if r_start[rep] is None: + 917 r_start_index.append(0) + 918 else: + 919 try: + 920 r_start_index.append(configlist[-1].index(r_start[rep])) + 921 except ValueError: + 922 raise Exception('Config %d not in file with range [%d, %d]' % ( + 923 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None + 924 + 925 if r_stop[rep] is None: + 926 r_stop_index.append(len(configlist[-1]) - 1) + 927 else: + 928 try: + 929 r_stop_index.append(configlist[-1].index(r_stop[rep])) + 930 except ValueError: + 931 raise Exception('Config %d not in file with range [%d, %d]' % ( + 932 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None + 933 + 934 if version in ['sfqcd']: + 935 cstepsize = cmax / ncs + 936 index_aim = round(c / cstepsize) + 937 else: + 938 t_aim = (c * L) ** 2 / 8 + 939 index_aim = round(t_aim / eps / dn) + 940 + 941 Q_sum = [] + 942 for i, item in enumerate(Q): + 943 if sum_t is True: + 944 Q_sum.append([sum(item[current:current + tmax]) + 945 for current in range(0, len(item), tmax)]) + 946 else: + 947 Q_sum.append([item[int(tmax / 2)]]) + 948 Q_top = [] + 949 if version in ['sfqcd']: + 950 for i in range(len(Q_sum) // (ncs + 1)): + 951 Q_top.append(Q_sum[i * (ncs + 1) + index_aim][0]) + 952 else: + 953 for i in range(len(Q) // dtr_cnfg): + 954 Q_top.append(Q_sum[dtr_cnfg * i][index_aim]) + 955 if len(Q_top) != len(traj_list) // dtr_cnfg: + 956 raise Exception("qtops and traj_list dont have the same length") + 957 + 958 if kwargs.get('integer_charge', False): + 959 Q_top = [round(q) for q in Q_top] + 960 + 961 truncated_file = file[:-len(postfix)] 962 - 963 Returns - 964 ------- - 965 reto : Obs - 966 projection to the topological charge sector defined by target - 967 """ - 968 if qtop.reweighted: - 969 raise Exception('You can not use a reweighted observable for reweighting!') - 970 - 971 proj_qtop = [] - 972 for n in qtop.deltas: - 973 proj_qtop.append(np.array([1 if round(qtop.r_values[n] + q) == target else 0 for q in qtop.deltas[n]])) + 963 if "names" not in kwargs: + 964 try: + 965 idx = truncated_file.index('r') + 966 except Exception: + 967 if "names" not in kwargs: + 968 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") + 969 ens_name = truncated_file[:idx] + 970 rep_names.append(ens_name + '|' + truncated_file[idx:].split(".")[0]) + 971 else: + 972 names = kwargs.get("names") + 973 rep_names = names 974 - 975 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) - 976 return reto - 977 + 975 deltas.append(Q_top) + 976 + 977 rep_names = _sort_names(rep_names) 978 - 979def read_qtop_sector(path, prefix, c, target=0, **kwargs): - 980 """Constructs reweighting factors to a specified topological sector. - 981 - 982 Parameters - 983 ---------- - 984 path : str - 985 path of the measurement files - 986 prefix : str - 987 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat - 988 c : double - 989 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L - 990 target : int - 991 Specifies the topological sector to be reweighted to (default 0) - 992 dtr_cnfg : int - 993 (optional) parameter that specifies the number of trajectories - 994 between two configs. - 995 if it is not set, the distance between two measurements - 996 in the file is assumed to be the distance between two configurations. - 997 steps : int - 998 (optional) Distance between two configurations in units of trajectories / - 999 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given -1000 version : str -1001 version string of the openQCD (sfqcd) version used to create -1002 the ensemble. Default is 2.0. May also be set to sfqcd. -1003 L : int -1004 spatial length of the lattice in L/a. -1005 HAS to be set if version != sfqcd, since openQCD does not provide -1006 this in the header -1007 r_start : list -1008 offset of the first ensemble, making it easier to match -1009 later on with other Obs -1010 r_stop : list -1011 last configurations that need to be read (per replicum) -1012 files : list -1013 specify the exact files that need to be read -1014 from path, practical if e.g. only one replicum is needed -1015 names : list -1016 Alternative labeling for replicas/ensembles. -1017 Has to have the appropriate length -1018 Zeuthen_flow : bool -1019 (optional) If True, the Zeuthen flow is used for Qtop. Only possible -1020 for version=='sfqcd' If False, the Wilson flow is used. -1021 -1022 Returns -1023 ------- -1024 reto : Obs -1025 projection to the topological charge sector defined by target -1026 """ -1027 -1028 if not isinstance(target, int): -1029 raise Exception("'target' has to be an integer.") -1030 -1031 kwargs['integer_charge'] = True -1032 qtop = read_qtop(path, prefix, c, **kwargs) -1033 -1034 return qtop_projection(qtop, target=target) -1035 -1036 -1037def read_ms5_xsf(path, prefix, qc, corr, sep="r", **kwargs): -1038 """ -1039 Read data from files in the specified directory with the specified prefix and quark combination extension, and return a `Corr` object containing the data. -1040 -1041 Parameters -1042 ---------- -1043 path : str -1044 The directory to search for the files in. -1045 prefix : str -1046 The prefix to match the files against. -1047 qc : str -1048 The quark combination extension to match the files against. -1049 corr : str -1050 The correlator to extract data for. -1051 sep : str, optional -1052 The separator to use when parsing the replika names. -1053 **kwargs -1054 Additional keyword arguments. The following keyword arguments are recognized: + 979 idl = [range(int(configlist[rep][r_start_index[rep]]), int(configlist[rep][r_stop_index[rep]]) + 1, 1) for rep in range(len(deltas))] + 980 deltas = [deltas[nrep][r_start_index[nrep]:r_stop_index[nrep] + 1] for nrep in range(len(deltas))] + 981 result = Obs(deltas, rep_names, idl=idl) + 982 result.tag = {"T": tmax - 1, + 983 "L": L} + 984 return result + 985 + 986 + 987def qtop_projection(qtop, target=0): + 988 """Returns the projection to the topological charge sector defined by target. + 989 + 990 Parameters + 991 ---------- + 992 path : Obs + 993 Topological charge. + 994 target : int + 995 Specifies the topological sector to be reweighted to (default 0) + 996 + 997 Returns + 998 ------- + 999 reto : Obs +1000 projection to the topological charge sector defined by target +1001 """ +1002 if qtop.reweighted: +1003 raise Exception('You can not use a reweighted observable for reweighting!') +1004 +1005 proj_qtop = [] +1006 for n in qtop.deltas: +1007 proj_qtop.append(np.array([1 if round(qtop.r_values[n] + q) == target else 0 for q in qtop.deltas[n]])) +1008 +1009 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) +1010 return reto +1011 +1012 +1013def read_qtop_sector(path, prefix, c, target=0, **kwargs): +1014 """Constructs reweighting factors to a specified topological sector. +1015 +1016 Parameters +1017 ---------- +1018 path : str +1019 path of the measurement files +1020 prefix : str +1021 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat +1022 c : double +1023 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L +1024 target : int +1025 Specifies the topological sector to be reweighted to (default 0) +1026 dtr_cnfg : int +1027 (optional) parameter that specifies the number of trajectories +1028 between two configs. +1029 if it is not set, the distance between two measurements +1030 in the file is assumed to be the distance between two configurations. +1031 steps : int +1032 (optional) Distance between two configurations in units of trajectories / +1033 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given +1034 version : str +1035 version string of the openQCD (sfqcd) version used to create +1036 the ensemble. Default is 2.0. May also be set to sfqcd. +1037 L : int +1038 spatial length of the lattice in L/a. +1039 HAS to be set if version != sfqcd, since openQCD does not provide +1040 this in the header +1041 r_start : list +1042 offset of the first ensemble, making it easier to match +1043 later on with other Obs +1044 r_stop : list +1045 last configurations that need to be read (per replicum) +1046 files : list +1047 specify the exact files that need to be read +1048 from path, practical if e.g. only one replicum is needed +1049 names : list +1050 Alternative labeling for replicas/ensembles. +1051 Has to have the appropriate length +1052 Zeuthen_flow : bool +1053 (optional) If True, the Zeuthen flow is used for Qtop. Only possible +1054 for version=='sfqcd' If False, the Wilson flow is used. 1055 -1056 - names (List[str]): A list of names to use for the replicas. -1057 -1058 Returns -1059 ------- -1060 Corr -1061 A complex valued `Corr` object containing the data read from the files. In case of boudary to bulk correlators. -1062 or -1063 CObs -1064 A complex valued `CObs` object containing the data read from the files. In case of boudary to boundary correlators. -1065 -1066 -1067 Raises -1068 ------ -1069 FileNotFoundError -1070 If no files matching the specified prefix and quark combination extension are found in the specified directory. -1071 IOError -1072 If there is an error reading a file. -1073 struct.error -1074 If there is an error unpacking binary data. -1075 """ -1076 -1077 # found = [] -1078 files = [] -1079 names = [] -1080 -1081 # test if the input is correct -1082 if qc not in ['dd', 'ud', 'du', 'uu']: -1083 raise Exception("Unknown quark conbination!") -1084 -1085 if corr not in ["gS", "gP", "gA", "gV", "gVt", "lA", "lV", "lVt", "lT", "lTt", "g1", "l1"]: -1086 raise Exception("Unknown correlator!") -1087 -1088 if "files" in kwargs: -1089 known_files = kwargs.get("files") -1090 else: -1091 known_files = [] -1092 files = _find_files(path, prefix, "ms5_xsf_" + qc, "dat", known_files=known_files) -1093 -1094 if "names" in kwargs: -1095 names = kwargs.get("names") -1096 else: -1097 for f in files: -1098 if not sep == "": -1099 se = f.split(".")[0] -1100 for s in f.split(".")[1:-2]: -1101 se += "." + s -1102 names.append(se.split(sep)[0] + "|r" + se.split(sep)[1]) -1103 else: -1104 names.append(prefix) -1105 -1106 names = sorted(names) -1107 files = sorted(files) -1108 -1109 cnfgs = [] -1110 realsamples = [] -1111 imagsamples = [] -1112 repnum = 0 -1113 for file in files: -1114 with open(path + "/" + file, "rb") as fp: -1115 -1116 t = fp.read(8) -1117 kappa = struct.unpack('d', t)[0] -1118 t = fp.read(8) -1119 csw = struct.unpack('d', t)[0] -1120 t = fp.read(8) -1121 dF = struct.unpack('d', t)[0] -1122 t = fp.read(8) -1123 zF = struct.unpack('d', t)[0] -1124 -1125 t = fp.read(4) -1126 tmax = struct.unpack('i', t)[0] -1127 t = fp.read(4) -1128 bnd = struct.unpack('i', t)[0] -1129 -1130 placesBI = ["gS", "gP", -1131 "gA", "gV", -1132 "gVt", "lA", -1133 "lV", "lVt", -1134 "lT", "lTt"] -1135 placesBB = ["g1", "l1"] -1136 -1137 # the chunks have the following structure: -1138 # confignumber, 10x timedependent complex correlators as doubles, 2x timeindependent complex correlators as doubles +1056 Returns +1057 ------- +1058 reto : Obs +1059 projection to the topological charge sector defined by target +1060 """ +1061 +1062 if not isinstance(target, int): +1063 raise Exception("'target' has to be an integer.") +1064 +1065 kwargs['integer_charge'] = True +1066 qtop = read_qtop(path, prefix, c, **kwargs) +1067 +1068 return qtop_projection(qtop, target=target) +1069 +1070 +1071def read_ms5_xsf(path, prefix, qc, corr, sep="r", **kwargs): +1072 """ +1073 Read data from files in the specified directory with the specified prefix and quark combination extension, and return a `Corr` object containing the data. +1074 +1075 Parameters +1076 ---------- +1077 path : str +1078 The directory to search for the files in. +1079 prefix : str +1080 The prefix to match the files against. +1081 qc : str +1082 The quark combination extension to match the files against. +1083 corr : str +1084 The correlator to extract data for. +1085 sep : str, optional +1086 The separator to use when parsing the replika names. +1087 **kwargs +1088 Additional keyword arguments. The following keyword arguments are recognized: +1089 +1090 - names (List[str]): A list of names to use for the replicas. +1091 +1092 Returns +1093 ------- +1094 Corr +1095 A complex valued `Corr` object containing the data read from the files. In case of boudary to bulk correlators. +1096 or +1097 CObs +1098 A complex valued `CObs` object containing the data read from the files. In case of boudary to boundary correlators. +1099 +1100 +1101 Raises +1102 ------ +1103 FileNotFoundError +1104 If no files matching the specified prefix and quark combination extension are found in the specified directory. +1105 IOError +1106 If there is an error reading a file. +1107 struct.error +1108 If there is an error unpacking binary data. +1109 """ +1110 +1111 # found = [] +1112 files = [] +1113 names = [] +1114 +1115 # test if the input is correct +1116 if qc not in ['dd', 'ud', 'du', 'uu']: +1117 raise Exception("Unknown quark conbination!") +1118 +1119 if corr not in ["gS", "gP", "gA", "gV", "gVt", "lA", "lV", "lVt", "lT", "lTt", "g1", "l1"]: +1120 raise Exception("Unknown correlator!") +1121 +1122 if "files" in kwargs: +1123 known_files = kwargs.get("files") +1124 else: +1125 known_files = [] +1126 files = _find_files(path, prefix, "ms5_xsf_" + qc, "dat", known_files=known_files) +1127 +1128 if "names" in kwargs: +1129 names = kwargs.get("names") +1130 else: +1131 for f in files: +1132 if not sep == "": +1133 se = f.split(".")[0] +1134 for s in f.split(".")[1:-2]: +1135 se += "." + s +1136 names.append(se.split(sep)[0] + "|r" + se.split(sep)[1]) +1137 else: +1138 names.append(prefix) 1139 -1140 chunksize = 4 + (8 * 2 * tmax * 10) + (8 * 2 * 2) -1141 packstr = '=i' + ('d' * 2 * tmax * 10) + ('d' * 2 * 2) -1142 cnfgs.append([]) -1143 realsamples.append([]) -1144 imagsamples.append([]) -1145 for t in range(tmax): -1146 realsamples[repnum].append([]) -1147 imagsamples[repnum].append([]) -1148 -1149 while True: -1150 cnfgt = fp.read(chunksize) -1151 if not cnfgt: -1152 break -1153 asascii = struct.unpack(packstr, cnfgt) -1154 cnfg = asascii[0] -1155 cnfgs[repnum].append(cnfg) -1156 -1157 if corr not in placesBB: -1158 tmpcorr = asascii[1 + 2 * tmax * placesBI.index(corr):1 + 2 * tmax * placesBI.index(corr) + 2 * tmax] -1159 else: -1160 tmpcorr = asascii[1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr):1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr) + 2] -1161 -1162 corrres = [[], []] -1163 for i in range(len(tmpcorr)): -1164 corrres[i % 2].append(tmpcorr[i]) -1165 for t in range(int(len(tmpcorr) / 2)): -1166 realsamples[repnum][t].append(corrres[0][t]) -1167 for t in range(int(len(tmpcorr) / 2)): -1168 imagsamples[repnum][t].append(corrres[1][t]) -1169 repnum += 1 +1140 names = sorted(names) +1141 files = sorted(files) +1142 +1143 cnfgs = [] +1144 realsamples = [] +1145 imagsamples = [] +1146 repnum = 0 +1147 for file in files: +1148 with open(path + "/" + file, "rb") as fp: +1149 +1150 t = fp.read(8) +1151 kappa = struct.unpack('d', t)[0] +1152 t = fp.read(8) +1153 csw = struct.unpack('d', t)[0] +1154 t = fp.read(8) +1155 dF = struct.unpack('d', t)[0] +1156 t = fp.read(8) +1157 zF = struct.unpack('d', t)[0] +1158 +1159 t = fp.read(4) +1160 tmax = struct.unpack('i', t)[0] +1161 t = fp.read(4) +1162 bnd = struct.unpack('i', t)[0] +1163 +1164 placesBI = ["gS", "gP", +1165 "gA", "gV", +1166 "gVt", "lA", +1167 "lV", "lVt", +1168 "lT", "lTt"] +1169 placesBB = ["g1", "l1"] 1170 -1171 s = "Read correlator " + corr + " from " + str(repnum) + " replika with " + str(len(realsamples[0][t])) -1172 for rep in range(1, repnum): -1173 s += ", " + str(len(realsamples[rep][t])) -1174 s += " samples" -1175 print(s) -1176 print("Asserted run parameters:\n T:", tmax, "kappa:", kappa, "csw:", csw, "dF:", dF, "zF:", zF, "bnd:", bnd) -1177 -1178 # we have the data now... but we need to re format the whole thing and put it into Corr objects. -1179 -1180 compObs = [] -1181 -1182 for t in range(int(len(tmpcorr) / 2)): -1183 compObs.append(CObs(Obs([realsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs), -1184 Obs([imagsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs))) -1185 -1186 if len(compObs) == 1: -1187 return compObs[0] -1188 else: -1189 return Corr(compObs) +1171 # the chunks have the following structure: +1172 # confignumber, 10x timedependent complex correlators as doubles, 2x timeindependent complex correlators as doubles +1173 +1174 chunksize = 4 + (8 * 2 * tmax * 10) + (8 * 2 * 2) +1175 packstr = '=i' + ('d' * 2 * tmax * 10) + ('d' * 2 * 2) +1176 cnfgs.append([]) +1177 realsamples.append([]) +1178 imagsamples.append([]) +1179 for t in range(tmax): +1180 realsamples[repnum].append([]) +1181 imagsamples[repnum].append([]) +1182 +1183 while True: +1184 cnfgt = fp.read(chunksize) +1185 if not cnfgt: +1186 break +1187 asascii = struct.unpack(packstr, cnfgt) +1188 cnfg = asascii[0] +1189 cnfgs[repnum].append(cnfg) +1190 +1191 if corr not in placesBB: +1192 tmpcorr = asascii[1 + 2 * tmax * placesBI.index(corr):1 + 2 * tmax * placesBI.index(corr) + 2 * tmax] +1193 else: +1194 tmpcorr = asascii[1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr):1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr) + 2] +1195 +1196 corrres = [[], []] +1197 for i in range(len(tmpcorr)): +1198 corrres[i % 2].append(tmpcorr[i]) +1199 for t in range(int(len(tmpcorr) / 2)): +1200 realsamples[repnum][t].append(corrres[0][t]) +1201 for t in range(int(len(tmpcorr) / 2)): +1202 imagsamples[repnum][t].append(corrres[1][t]) +1203 repnum += 1 +1204 +1205 s = "Read correlator " + corr + " from " + str(repnum) + " replika with " + str(len(realsamples[0][t])) +1206 for rep in range(1, repnum): +1207 s += ", " + str(len(realsamples[rep][t])) +1208 s += " samples" +1209 print(s) +1210 print("Asserted run parameters:\n T:", tmax, "kappa:", kappa, "csw:", csw, "dF:", dF, "zF:", zF, "bnd:", bnd) +1211 +1212 # we have the data now... but we need to re format the whole thing and put it into Corr objects. +1213 +1214 compObs = [] +1215 +1216 for t in range(int(len(tmpcorr) / 2)): +1217 compObs.append(CObs(Obs([realsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs), +1218 Obs([imagsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs))) +1219 +1220 if len(compObs) == 1: +1221 return compObs[0] +1222 else: +1223 return Corr(compObs) @@ -1298,221 +1332,223 @@ -
56def read_rwms(path, prefix, version='2.0', names=None, **kwargs): - 57 """Read rwms format from given folder structure. Returns a list of length nrw - 58 - 59 Parameters - 60 ---------- - 61 path : str - 62 path that contains the data files - 63 prefix : str - 64 all files in path that start with prefix are considered as input files. - 65 May be used together postfix to consider only special file endings. - 66 Prefix is ignored, if the keyword 'files' is used. - 67 version : str - 68 version of openQCD, default 2.0 - 69 names : list - 70 list of names that is assigned to the data according according - 71 to the order in the file list. Use careful, if you do not provide file names! - 72 r_start : list - 73 list which contains the first config to be read for each replicum - 74 r_stop : list - 75 list which contains the last config to be read for each replicum - 76 r_step : int - 77 integer that defines a fixed step size between two measurements (in units of configs) - 78 If not given, r_step=1 is assumed. - 79 postfix : str - 80 postfix of the file to read, e.g. '.ms1' for openQCD-files - 81 files : list - 82 list which contains the filenames to be read. No automatic detection of - 83 files performed if given. - 84 print_err : bool - 85 Print additional information that is useful for debugging. - 86 - 87 Returns - 88 ------- - 89 rwms : Obs - 90 Reweighting factors read - 91 """ - 92 known_oqcd_versions = ['1.4', '1.6', '2.0'] - 93 if not (version in known_oqcd_versions): - 94 raise Exception('Unknown openQCD version defined!') - 95 print("Working with openQCD version " + version) - 96 if 'postfix' in kwargs: - 97 postfix = kwargs.get('postfix') - 98 else: - 99 postfix = '' -100 -101 if 'files' in kwargs: -102 known_files = kwargs.get('files') -103 else: -104 known_files = [] -105 -106 ls = _find_files(path, prefix, postfix, 'dat', known_files=known_files) -107 -108 replica = len(ls) -109 -110 if 'r_start' in kwargs: -111 r_start = kwargs.get('r_start') -112 if len(r_start) != replica: -113 raise Exception('r_start does not match number of replicas') -114 r_start = [o if o else None for o in r_start] -115 else: -116 r_start = [None] * replica -117 -118 if 'r_stop' in kwargs: -119 r_stop = kwargs.get('r_stop') -120 if len(r_stop) != replica: -121 raise Exception('r_stop does not match number of replicas') -122 else: -123 r_stop = [None] * replica -124 -125 if 'r_step' in kwargs: -126 r_step = kwargs.get('r_step') +@@ -1569,246 +1605,246 @@ Reweighting factors read85def read_rwms(path, prefix, version='2.0', names=None, **kwargs): + 86 """Read rwms format from given folder structure. Returns a list of length nrw + 87 + 88 Parameters + 89 ---------- + 90 path : str + 91 path that contains the data files + 92 prefix : str + 93 all files in path that start with prefix are considered as input files. + 94 May be used together postfix to consider only special file endings. + 95 Prefix is ignored, if the keyword 'files' is used. + 96 version : str + 97 version of openQCD, default 2.0 + 98 names : list + 99 list of names that is assigned to the data according according +100 to the order in the file list. Use careful, if you do not provide file names! +101 r_start : list +102 list which contains the first config to be read for each replicum +103 r_stop : list +104 list which contains the last config to be read for each replicum +105 r_step : int +106 integer that defines a fixed step size between two measurements (in units of configs) +107 If not given, r_step=1 is assumed. +108 postfix : str +109 postfix of the file to read, e.g. '.ms1' for openQCD-files +110 files : list +111 list which contains the filenames to be read. No automatic detection of +112 files performed if given. +113 print_err : bool +114 Print additional information that is useful for debugging. +115 +116 Returns +117 ------- +118 rwms : Obs +119 Reweighting factors read +120 """ +121 known_oqcd_versions = ['1.4', '1.6', '2.0'] +122 if not (version in known_oqcd_versions): +123 raise Exception('Unknown openQCD version defined!') +124 print("Working with openQCD version " + version) +125 if 'postfix' in kwargs: +126 postfix = kwargs.get('postfix') 127 else: -128 r_step = 1 +128 postfix = '' 129 -130 print('Read reweighting factors from', prefix[:-1], ',', -131 replica, 'replica', end='') -132 -133 if names is None: -134 rep_names = [] -135 for entry in ls: -136 truncated_entry = entry -137 suffixes = [".dat", ".rwms", ".ms1"] -138 for suffix in suffixes: -139 if truncated_entry.endswith(suffix): -140 truncated_entry = truncated_entry[0:-len(suffix)] -141 idx = truncated_entry.index('r') -142 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) -143 else: -144 rep_names = names -145 -146 print_err = 0 -147 if 'print_err' in kwargs: -148 print_err = 1 -149 print() -150 -151 deltas = [] -152 -153 configlist = [] -154 r_start_index = [] -155 r_stop_index = [] -156 -157 for rep in range(replica): -158 tmp_array = [] -159 with open(path + '/' + ls[rep], 'rb') as fp: -160 -161 t = fp.read(4) # number of reweighting factors -162 if rep == 0: -163 nrw = struct.unpack('i', t)[0] -164 if version == '2.0': -165 nrw = int(nrw / 2) -166 for k in range(nrw): -167 deltas.append([]) -168 else: -169 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): -170 raise Exception('Error: different number of reweighting factors for replicum', rep) -171 -172 for k in range(nrw): -173 tmp_array.append([]) +130 if 'files' in kwargs: +131 known_files = kwargs.get('files') +132 else: +133 known_files = [] +134 +135 ls = _find_files(path, prefix, postfix, 'dat', known_files=known_files) +136 +137 replica = len(ls) +138 +139 if 'r_start' in kwargs: +140 r_start = kwargs.get('r_start') +141 if len(r_start) != replica: +142 raise Exception('r_start does not match number of replicas') +143 r_start = [o if o else None for o in r_start] +144 else: +145 r_start = [None] * replica +146 +147 if 'r_stop' in kwargs: +148 r_stop = kwargs.get('r_stop') +149 if len(r_stop) != replica: +150 raise Exception('r_stop does not match number of replicas') +151 else: +152 r_stop = [None] * replica +153 +154 if 'r_step' in kwargs: +155 r_step = kwargs.get('r_step') +156 else: +157 r_step = 1 +158 +159 print('Read reweighting factors from', prefix[:-1], ',', +160 replica, 'replica', end='') +161 +162 if names is None: +163 rep_names = [] +164 for entry in ls: +165 truncated_entry = entry +166 suffixes = [".dat", ".rwms", ".ms1"] +167 for suffix in suffixes: +168 if truncated_entry.endswith(suffix): +169 truncated_entry = truncated_entry[0:-len(suffix)] +170 idx = truncated_entry.index('r') +171 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) +172 else: +173 rep_names = names 174 -175 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files -176 nfct = [] -177 if version in ['1.6', '2.0']: -178 for i in range(nrw): -179 t = fp.read(4) -180 nfct.append(struct.unpack('i', t)[0]) -181 else: -182 for i in range(nrw): -183 nfct.append(1) -184 -185 nsrc = [] -186 for i in range(nrw): -187 t = fp.read(4) -188 nsrc.append(struct.unpack('i', t)[0]) -189 if version == '2.0': -190 if not struct.unpack('i', fp.read(4))[0] == 0: -191 raise Exception("You are using the input for openQCD version 2.0, this is not correct.") -192 -193 configlist.append([]) -194 while True: -195 t = fp.read(4) -196 if len(t) < 4: -197 break -198 config_no = struct.unpack('i', t)[0] -199 configlist[-1].append(config_no) -200 for i in range(nrw): -201 if (version == '2.0'): -202 tmpd = _read_array_openQCD2(fp) -203 tmpd = _read_array_openQCD2(fp) -204 tmp_rw = tmpd['arr'] -205 tmp_nfct = 1.0 -206 for j in range(tmpd['n'][0]): -207 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) -208 if print_err: -209 print(config_no, i, j, -210 np.mean(np.exp(-np.asarray(tmp_rw[j]))), -211 np.std(np.exp(-np.asarray(tmp_rw[j])))) -212 print('Sources:', -213 np.exp(-np.asarray(tmp_rw[j]))) -214 print('Partial factor:', tmp_nfct) -215 elif version == '1.6' or version == '1.4': -216 tmp_nfct = 1.0 -217 for j in range(nfct[i]): -218 t = fp.read(8 * nsrc[i]) -219 t = fp.read(8 * nsrc[i]) -220 tmp_rw = struct.unpack('d' * nsrc[i], t) -221 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) -222 if print_err: -223 print(config_no, i, j, -224 np.mean(np.exp(-np.asarray(tmp_rw))), -225 np.std(np.exp(-np.asarray(tmp_rw)))) -226 print('Sources:', np.exp(-np.asarray(tmp_rw))) -227 print('Partial factor:', tmp_nfct) -228 tmp_array[i].append(tmp_nfct) -229 -230 diffmeas = configlist[-1][-1] - configlist[-1][-2] -231 configlist[-1] = [item // diffmeas for item in configlist[-1]] -232 if configlist[-1][0] > 1 and diffmeas > 1: -233 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') -234 offset = configlist[-1][0] - 1 -235 configlist[-1] = [item - offset for item in configlist[-1]] -236 -237 if r_start[rep] is None: -238 r_start_index.append(0) -239 else: -240 try: -241 r_start_index.append(configlist[-1].index(r_start[rep])) -242 except ValueError: -243 raise Exception('Config %d not in file with range [%d, %d]' % ( -244 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None -245 -246 if r_stop[rep] is None: -247 r_stop_index.append(len(configlist[-1]) - 1) -248 else: -249 try: -250 r_stop_index.append(configlist[-1].index(r_stop[rep])) -251 except ValueError: -252 raise Exception('Config %d not in file with range [%d, %d]' % ( -253 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None -254 -255 for k in range(nrw): -256 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) -257 -258 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): -259 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) -260 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] -261 if np.any([step != 1 for step in stepsizes]): -262 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) -263 -264 print(',', nrw, 'reweighting factors with', nsrc, 'sources') -265 result = [] -266 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] +175 rep_names = _sort_names(rep_names) +176 +177 print_err = 0 +178 if 'print_err' in kwargs: +179 print_err = 1 +180 print() +181 +182 deltas = [] +183 +184 configlist = [] +185 r_start_index = [] +186 r_stop_index = [] +187 +188 for rep in range(replica): +189 tmp_array = [] +190 with open(path + '/' + ls[rep], 'rb') as fp: +191 +192 t = fp.read(4) # number of reweighting factors +193 if rep == 0: +194 nrw = struct.unpack('i', t)[0] +195 if version == '2.0': +196 nrw = int(nrw / 2) +197 for k in range(nrw): +198 deltas.append([]) +199 else: +200 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): +201 raise Exception('Error: different number of reweighting factors for replicum', rep) +202 +203 for k in range(nrw): +204 tmp_array.append([]) +205 +206 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files +207 nfct = [] +208 if version in ['1.6', '2.0']: +209 for i in range(nrw): +210 t = fp.read(4) +211 nfct.append(struct.unpack('i', t)[0]) +212 else: +213 for i in range(nrw): +214 nfct.append(1) +215 +216 nsrc = [] +217 for i in range(nrw): +218 t = fp.read(4) +219 nsrc.append(struct.unpack('i', t)[0]) +220 if version == '2.0': +221 if not struct.unpack('i', fp.read(4))[0] == 0: +222 raise Exception("You are using the input for openQCD version 2.0, this is not correct.") +223 +224 configlist.append([]) +225 while True: +226 t = fp.read(4) +227 if len(t) < 4: +228 break +229 config_no = struct.unpack('i', t)[0] +230 configlist[-1].append(config_no) +231 for i in range(nrw): +232 if (version == '2.0'): +233 tmpd = _read_array_openQCD2(fp) +234 tmpd = _read_array_openQCD2(fp) +235 tmp_rw = tmpd['arr'] +236 tmp_nfct = 1.0 +237 for j in range(tmpd['n'][0]): +238 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) +239 if print_err: +240 print(config_no, i, j, +241 np.mean(np.exp(-np.asarray(tmp_rw[j]))), +242 np.std(np.exp(-np.asarray(tmp_rw[j])))) +243 print('Sources:', +244 np.exp(-np.asarray(tmp_rw[j]))) +245 print('Partial factor:', tmp_nfct) +246 elif version == '1.6' or version == '1.4': +247 tmp_nfct = 1.0 +248 for j in range(nfct[i]): +249 t = fp.read(8 * nsrc[i]) +250 t = fp.read(8 * nsrc[i]) +251 tmp_rw = struct.unpack('d' * nsrc[i], t) +252 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) +253 if print_err: +254 print(config_no, i, j, +255 np.mean(np.exp(-np.asarray(tmp_rw))), +256 np.std(np.exp(-np.asarray(tmp_rw)))) +257 print('Sources:', np.exp(-np.asarray(tmp_rw))) +258 print('Partial factor:', tmp_nfct) +259 tmp_array[i].append(tmp_nfct) +260 +261 diffmeas = configlist[-1][-1] - configlist[-1][-2] +262 configlist[-1] = [item // diffmeas for item in configlist[-1]] +263 if configlist[-1][0] > 1 and diffmeas > 1: +264 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') +265 offset = configlist[-1][0] - 1 +266 configlist[-1] = [item - offset for item in configlist[-1]] 267 -268 for t in range(nrw): -269 result.append(Obs(deltas[t], rep_names, idl=idl)) -270 return result +268 if r_start[rep] is None: +269 r_start_index.append(0) +270 else: +271 try: +272 r_start_index.append(configlist[-1].index(r_start[rep])) +273 except ValueError: +274 raise Exception('Config %d not in file with range [%d, %d]' % ( +275 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None +276 +277 if r_stop[rep] is None: +278 r_stop_index.append(len(configlist[-1]) - 1) +279 else: +280 try: +281 r_stop_index.append(configlist[-1].index(r_stop[rep])) +282 except ValueError: +283 raise Exception('Config %d not in file with range [%d, %d]' % ( +284 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None +285 +286 for k in range(nrw): +287 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) +288 +289 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): +290 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) +291 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] +292 if np.any([step != 1 for step in stepsizes]): +293 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) +294 +295 print(',', nrw, 'reweighting factors with', nsrc, 'sources') +296 result = [] +297 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] +298 +299 for t in range(nrw): +300 result.append(Obs(deltas[t], rep_names, idl=idl)) +301 return result
273def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): -274 """Extract t0 from given .ms.dat files. Returns t0 as Obs. -275 -276 It is assumed that all boundary effects have -277 sufficiently decayed at x0=xmin. -278 The data around the zero crossing of t^2<E> - 0.3 -279 is fitted with a linear function -280 from which the exact root is extracted. -281 -282 It is assumed that one measurement is performed for each config. -283 If this is not the case, the resulting idl, as well as the handling -284 of r_start, r_stop and r_step is wrong and the user has to correct -285 this in the resulting observable. -286 -287 Parameters -288 ---------- -289 path : str -290 Path to .ms.dat files -291 prefix : str -292 Ensemble prefix -293 dtr_read : int -294 Determines how many trajectories should be skipped -295 when reading the ms.dat files. -296 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. -297 xmin : int -298 First timeslice where the boundary -299 effects have sufficiently decayed. -300 spatial_extent : int -301 spatial extent of the lattice, required for normalization. -302 fit_range : int -303 Number of data points left and right of the zero -304 crossing to be included in the linear fit. (Default: 5) -305 r_start : list -306 list which contains the first config to be read for each replicum. -307 r_stop : list -308 list which contains the last config to be read for each replicum. -309 r_step : int -310 integer that defines a fixed step size between two measurements (in units of configs) -311 If not given, r_step=1 is assumed. -312 plaquette : bool -313 If true extract the plaquette estimate of t0 instead. -314 names : list -315 list of names that is assigned to the data according according -316 to the order in the file list. Use careful, if you do not provide file names! -317 files : list -318 list which contains the filenames to be read. No automatic detection of -319 files performed if given. -320 plot_fit : bool -321 If true, the fit for the extraction of t0 is shown together with the data. -322 assume_thermalization : bool -323 If True: If the first record divided by the distance between two measurements is larger than -324 1, it is assumed that this is due to thermalization and the first measurement belongs -325 to the first config (default). -326 If False: The config numbers are assumed to be traj_number // difference -327 -328 Returns -329 ------- -330 t0 : Obs -331 Extracted t0 -332 """ -333 -334 if 'files' in kwargs: -335 known_files = kwargs.get('files') -336 else: -337 known_files = [] -338 -339 ls = _find_files(path, prefix, 'ms', 'dat', known_files=known_files) -340 -341 replica = len(ls) -342 -343 if 'r_start' in kwargs: -344 r_start = kwargs.get('r_start') -345 if len(r_start) != replica: -346 raise Exception('r_start does not match number of replicas') -347 r_start = [o if o else None for o in r_start] -348 else: -349 r_start = [None] * replica -350 -351 if 'r_stop' in kwargs: -352 r_stop = kwargs.get('r_stop') -353 if len(r_stop) != replica: -354 raise Exception('r_stop does not match number of replicas') -355 else: -356 r_stop = [None] * replica -357 -358 if 'r_step' in kwargs: -359 r_step = kwargs.get('r_step') -360 else: -361 r_step = 1 -362 -363 print('Extract t0 from', prefix, ',', replica, 'replica') +@@ -1889,57 +1925,57 @@ Extracted t0304def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): +305 """Extract t0 from given .ms.dat files. Returns t0 as Obs. +306 +307 It is assumed that all boundary effects have +308 sufficiently decayed at x0=xmin. +309 The data around the zero crossing of t^2<E> - 0.3 +310 is fitted with a linear function +311 from which the exact root is extracted. +312 +313 It is assumed that one measurement is performed for each config. +314 If this is not the case, the resulting idl, as well as the handling +315 of r_start, r_stop and r_step is wrong and the user has to correct +316 this in the resulting observable. +317 +318 Parameters +319 ---------- +320 path : str +321 Path to .ms.dat files +322 prefix : str +323 Ensemble prefix +324 dtr_read : int +325 Determines how many trajectories should be skipped +326 when reading the ms.dat files. +327 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. +328 xmin : int +329 First timeslice where the boundary +330 effects have sufficiently decayed. +331 spatial_extent : int +332 spatial extent of the lattice, required for normalization. +333 fit_range : int +334 Number of data points left and right of the zero +335 crossing to be included in the linear fit. (Default: 5) +336 r_start : list +337 list which contains the first config to be read for each replicum. +338 r_stop : list +339 list which contains the last config to be read for each replicum. +340 r_step : int +341 integer that defines a fixed step size between two measurements (in units of configs) +342 If not given, r_step=1 is assumed. +343 plaquette : bool +344 If true extract the plaquette estimate of t0 instead. +345 names : list +346 list of names that is assigned to the data according according +347 to the order in the file list. Use careful, if you do not provide file names! +348 files : list +349 list which contains the filenames to be read. No automatic detection of +350 files performed if given. +351 plot_fit : bool +352 If true, the fit for the extraction of t0 is shown together with the data. +353 assume_thermalization : bool +354 If True: If the first record divided by the distance between two measurements is larger than +355 1, it is assumed that this is due to thermalization and the first measurement belongs +356 to the first config (default). +357 If False: The config numbers are assumed to be traj_number // difference +358 +359 Returns +360 ------- +361 t0 : Obs +362 Extracted t0 +363 """ 364 -365 if 'names' in kwargs: -366 rep_names = kwargs.get('names') +365 if 'files' in kwargs: +366 known_files = kwargs.get('files') 367 else: -368 rep_names = [] -369 for entry in ls: -370 truncated_entry = entry.split('.')[0] -371 idx = truncated_entry.index('r') -372 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) +368 known_files = [] +369 +370 ls = _find_files(path, prefix, 'ms', 'dat', known_files=known_files) +371 +372 replica = len(ls) 373 -374 Ysum = [] -375 -376 configlist = [] -377 r_start_index = [] -378 r_stop_index = [] -379 -380 for rep in range(replica): +374 if 'r_start' in kwargs: +375 r_start = kwargs.get('r_start') +376 if len(r_start) != replica: +377 raise Exception('r_start does not match number of replicas') +378 r_start = [o if o else None for o in r_start] +379 else: +380 r_start = [None] * replica 381 -382 with open(path + '/' + ls[rep], 'rb') as fp: -383 t = fp.read(12) -384 header = struct.unpack('iii', t) -385 if rep == 0: -386 dn = header[0] -387 nn = header[1] -388 tmax = header[2] -389 elif dn != header[0] or nn != header[1] or tmax != header[2]: -390 raise Exception('Replica parameters do not match.') -391 -392 t = fp.read(8) -393 if rep == 0: -394 eps = struct.unpack('d', t)[0] -395 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) -396 elif eps != struct.unpack('d', t)[0]: -397 raise Exception('Values for eps do not match among replica.') -398 -399 Ysl = [] -400 -401 configlist.append([]) -402 while True: -403 t = fp.read(4) -404 if (len(t) < 4): -405 break -406 nc = struct.unpack('i', t)[0] -407 configlist[-1].append(nc) -408 -409 t = fp.read(8 * tmax * (nn + 1)) -410 if kwargs.get('plaquette'): -411 if nc % dtr_read == 0: -412 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) -413 t = fp.read(8 * tmax * (nn + 1)) -414 if not kwargs.get('plaquette'): -415 if nc % dtr_read == 0: -416 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) -417 t = fp.read(8 * tmax * (nn + 1)) -418 -419 Ysum.append([]) -420 for i, item in enumerate(Ysl): -421 Ysum[-1].append([np.mean(item[current + xmin: -422 current + tmax - xmin]) -423 for current in range(0, len(item), tmax)]) -424 -425 diffmeas = configlist[-1][-1] - configlist[-1][-2] -426 configlist[-1] = [item // diffmeas for item in configlist[-1]] -427 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: -428 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') -429 offset = configlist[-1][0] - 1 -430 configlist[-1] = [item - offset for item in configlist[-1]] +382 if 'r_stop' in kwargs: +383 r_stop = kwargs.get('r_stop') +384 if len(r_stop) != replica: +385 raise Exception('r_stop does not match number of replicas') +386 else: +387 r_stop = [None] * replica +388 +389 if 'r_step' in kwargs: +390 r_step = kwargs.get('r_step') +391 else: +392 r_step = 1 +393 +394 print('Extract t0 from', prefix, ',', replica, 'replica') +395 +396 if 'names' in kwargs: +397 rep_names = kwargs.get('names') +398 else: +399 rep_names = [] +400 for entry in ls: +401 truncated_entry = entry.split('.')[0] +402 idx = truncated_entry.index('r') +403 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) +404 +405 Ysum = [] +406 +407 configlist = [] +408 r_start_index = [] +409 r_stop_index = [] +410 +411 for rep in range(replica): +412 +413 with open(path + '/' + ls[rep], 'rb') as fp: +414 t = fp.read(12) +415 header = struct.unpack('iii', t) +416 if rep == 0: +417 dn = header[0] +418 nn = header[1] +419 tmax = header[2] +420 elif dn != header[0] or nn != header[1] or tmax != header[2]: +421 raise Exception('Replica parameters do not match.') +422 +423 t = fp.read(8) +424 if rep == 0: +425 eps = struct.unpack('d', t)[0] +426 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) +427 elif eps != struct.unpack('d', t)[0]: +428 raise Exception('Values for eps do not match among replica.') +429 +430 Ysl = [] 431 -432 if r_start[rep] is None: -433 r_start_index.append(0) -434 else: -435 try: -436 r_start_index.append(configlist[-1].index(r_start[rep])) -437 except ValueError: -438 raise Exception('Config %d not in file with range [%d, %d]' % ( -439 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None -440 -441 if r_stop[rep] is None: -442 r_stop_index.append(len(configlist[-1]) - 1) -443 else: -444 try: -445 r_stop_index.append(configlist[-1].index(r_stop[rep])) -446 except ValueError: -447 raise Exception('Config %d not in file with range [%d, %d]' % ( -448 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None +432 configlist.append([]) +433 while True: +434 t = fp.read(4) +435 if (len(t) < 4): +436 break +437 nc = struct.unpack('i', t)[0] +438 configlist[-1].append(nc) +439 +440 t = fp.read(8 * tmax * (nn + 1)) +441 if kwargs.get('plaquette'): +442 if nc % dtr_read == 0: +443 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) +444 t = fp.read(8 * tmax * (nn + 1)) +445 if not kwargs.get('plaquette'): +446 if nc % dtr_read == 0: +447 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) +448 t = fp.read(8 * tmax * (nn + 1)) 449 -450 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): -451 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) -452 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] -453 if np.any([step != 1 for step in stepsizes]): -454 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) +450 Ysum.append([]) +451 for i, item in enumerate(Ysl): +452 Ysum[-1].append([np.mean(item[current + xmin: +453 current + tmax - xmin]) +454 for current in range(0, len(item), tmax)]) 455 -456 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] -457 t2E_dict = {} -458 for n in range(nn + 1): -459 samples = [] -460 for nrep, rep in enumerate(Ysum): -461 samples.append([]) -462 for cnfg in rep: -463 samples[-1].append(cnfg[n]) -464 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] -465 new_obs = Obs(samples, rep_names, idl=idl) -466 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 -467 -468 zero_crossing = np.argmax(np.array( -469 [o.value for o in t2E_dict.values()]) > 0.0) -470 -471 x = list(t2E_dict.keys())[zero_crossing - fit_range: -472 zero_crossing + fit_range] -473 y = list(t2E_dict.values())[zero_crossing - fit_range: -474 zero_crossing + fit_range] -475 [o.gamma_method() for o in y] -476 -477 fit_result = fit_lin(x, y) -478 -479 if kwargs.get('plot_fit'): -480 plt.figure() -481 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) -482 ax0 = plt.subplot(gs[0]) -483 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] -484 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] -485 [o.gamma_method() for o in ymore] -486 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') -487 xplot = np.linspace(np.min(x), np.max(x)) -488 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] -489 [yi.gamma_method() for yi in yplot] -490 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) -491 retval = (-fit_result[0] / fit_result[1]) -492 retval.gamma_method() -493 ylim = ax0.get_ylim() -494 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) -495 ax0.set_ylim(ylim) -496 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') -497 xlim = ax0.get_xlim() +456 diffmeas = configlist[-1][-1] - configlist[-1][-2] +457 configlist[-1] = [item // diffmeas for item in configlist[-1]] +458 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: +459 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') +460 offset = configlist[-1][0] - 1 +461 configlist[-1] = [item - offset for item in configlist[-1]] +462 +463 if r_start[rep] is None: +464 r_start_index.append(0) +465 else: +466 try: +467 r_start_index.append(configlist[-1].index(r_start[rep])) +468 except ValueError: +469 raise Exception('Config %d not in file with range [%d, %d]' % ( +470 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None +471 +472 if r_stop[rep] is None: +473 r_stop_index.append(len(configlist[-1]) - 1) +474 else: +475 try: +476 r_stop_index.append(configlist[-1].index(r_stop[rep])) +477 except ValueError: +478 raise Exception('Config %d not in file with range [%d, %d]' % ( +479 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None +480 +481 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): +482 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) +483 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] +484 if np.any([step != 1 for step in stepsizes]): +485 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) +486 +487 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] +488 t2E_dict = {} +489 for n in range(nn + 1): +490 samples = [] +491 for nrep, rep in enumerate(Ysum): +492 samples.append([]) +493 for cnfg in rep: +494 samples[-1].append(cnfg[n]) +495 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] +496 new_obs = Obs(samples, rep_names, idl=idl) +497 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 498 -499 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] -500 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) -501 ax1 = plt.subplot(gs[1]) -502 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) -503 ax1.tick_params(direction='out') -504 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) -505 ax1.axhline(y=0.0, ls='--', color='k') -506 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') -507 ax1.set_xlim(xlim) -508 ax1.set_ylabel('Residuals') -509 ax1.set_xlabel(r'$t/a^2$') -510 -511 plt.draw() -512 return -fit_result[0] / fit_result[1] +499 zero_crossing = np.argmax(np.array( +500 [o.value for o in t2E_dict.values()]) > 0.0) +501 +502 x = list(t2E_dict.keys())[zero_crossing - fit_range: +503 zero_crossing + fit_range] +504 y = list(t2E_dict.values())[zero_crossing - fit_range: +505 zero_crossing + fit_range] +506 [o.gamma_method() for o in y] +507 +508 fit_result = fit_lin(x, y) +509 +510 if kwargs.get('plot_fit'): +511 plt.figure() +512 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) +513 ax0 = plt.subplot(gs[0]) +514 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] +515 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] +516 [o.gamma_method() for o in ymore] +517 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') +518 xplot = np.linspace(np.min(x), np.max(x)) +519 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] +520 [yi.gamma_method() for yi in yplot] +521 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) +522 retval = (-fit_result[0] / fit_result[1]) +523 retval.gamma_method() +524 ylim = ax0.get_ylim() +525 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) +526 ax0.set_ylim(ylim) +527 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') +528 xlim = ax0.get_xlim() +529 +530 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] +531 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) +532 ax1 = plt.subplot(gs[1]) +533 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) +534 ax1.tick_params(direction='out') +535 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) +536 ax1.axhline(y=0.0, ls='--', color='k') +537 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') +538 ax1.set_xlim(xlim) +539 ax1.set_ylabel('Residuals') +540 ax1.set_xlabel(r'$t/a^2$') +541 +542 plt.draw() +543 return -fit_result[0] / fit_result[1]
560def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): -561 """Read the topologial charge based on openQCD gradient flow measurements. -562 -563 Parameters -564 ---------- -565 path : str -566 path of the measurement files -567 prefix : str -568 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. -569 Ignored if file names are passed explicitly via keyword files. -570 c : double -571 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. -572 dtr_cnfg : int -573 (optional) parameter that specifies the number of measurements -574 between two configs. -575 If it is not set, the distance between two measurements -576 in the file is assumed to be the distance between two configurations. -577 steps : int -578 (optional) Distance between two configurations in units of trajectories / -579 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given -580 version : str -581 Either openQCD or sfqcd, depending on the data. -582 L : int -583 spatial length of the lattice in L/a. -584 HAS to be set if version != sfqcd, since openQCD does not provide -585 this in the header -586 r_start : list -587 list which contains the first config to be read for each replicum. -588 r_stop : list -589 list which contains the last config to be read for each replicum. -590 files : list -591 specify the exact files that need to be read -592 from path, practical if e.g. only one replicum is needed -593 postfix : str -594 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files -595 names : list -596 Alternative labeling for replicas/ensembles. -597 Has to have the appropriate length. -598 Zeuthen_flow : bool -599 (optional) If True, the Zeuthen flow is used for Qtop. Only possible -600 for version=='sfqcd' If False, the Wilson flow is used. -601 integer_charge : bool -602 If True, the charge is rounded towards the nearest integer on each config. -603 -604 Returns -605 ------- -606 result : Obs -607 Read topological charge -608 """ -609 -610 return _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version=version, obspos=0, **kwargs) +@@ -2009,76 +2045,76 @@ Read topological charge591def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): +592 """Read the topologial charge based on openQCD gradient flow measurements. +593 +594 Parameters +595 ---------- +596 path : str +597 path of the measurement files +598 prefix : str +599 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. +600 Ignored if file names are passed explicitly via keyword files. +601 c : double +602 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. +603 dtr_cnfg : int +604 (optional) parameter that specifies the number of measurements +605 between two configs. +606 If it is not set, the distance between two measurements +607 in the file is assumed to be the distance between two configurations. +608 steps : int +609 (optional) Distance between two configurations in units of trajectories / +610 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given +611 version : str +612 Either openQCD or sfqcd, depending on the data. +613 L : int +614 spatial length of the lattice in L/a. +615 HAS to be set if version != sfqcd, since openQCD does not provide +616 this in the header +617 r_start : list +618 list which contains the first config to be read for each replicum. +619 r_stop : list +620 list which contains the last config to be read for each replicum. +621 files : list +622 specify the exact files that need to be read +623 from path, practical if e.g. only one replicum is needed +624 postfix : str +625 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files +626 names : list +627 Alternative labeling for replicas/ensembles. +628 Has to have the appropriate length. +629 Zeuthen_flow : bool +630 (optional) If True, the Zeuthen flow is used for Qtop. Only possible +631 for version=='sfqcd' If False, the Wilson flow is used. +632 integer_charge : bool +633 If True, the charge is rounded towards the nearest integer on each config. +634 +635 Returns +636 ------- +637 result : Obs +638 Read topological charge +639 """ +640 +641 return _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version=version, obspos=0, **kwargs)
613def read_gf_coupling(path, prefix, c, dtr_cnfg=1, Zeuthen_flow=True, **kwargs): -614 """Read the gradient flow coupling based on sfqcd gradient flow measurements. See 1607.06423 for details. -615 -616 Note: The current implementation only works for c=0.3 and T=L. The definition of the coupling in 1607.06423 requires projection to topological charge zero which is not done within this function but has to be performed in a separate step. -617 -618 Parameters -619 ---------- -620 path : str -621 path of the measurement files -622 prefix : str -623 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. -624 Ignored if file names are passed explicitly via keyword files. -625 c : double -626 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. -627 dtr_cnfg : int -628 (optional) parameter that specifies the number of measurements -629 between two configs. -630 If it is not set, the distance between two measurements -631 in the file is assumed to be the distance between two configurations. -632 steps : int -633 (optional) Distance between two configurations in units of trajectories / -634 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given -635 r_start : list -636 list which contains the first config to be read for each replicum. -637 r_stop : list -638 list which contains the last config to be read for each replicum. -639 files : list -640 specify the exact files that need to be read -641 from path, practical if e.g. only one replicum is needed -642 names : list -643 Alternative labeling for replicas/ensembles. -644 Has to have the appropriate length. -645 postfix : str -646 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files -647 Zeuthen_flow : bool -648 (optional) If True, the Zeuthen flow is used for the coupling. If False, the Wilson flow is used. -649 """ -650 -651 if c != 0.3: -652 raise Exception("The required lattice norm is only implemented for c=0.3 at the moment.") -653 -654 plaq = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=6, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) -655 C2x1 = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=7, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) -656 L = plaq.tag["L"] -657 T = plaq.tag["T"] -658 -659 if T != L: -660 raise Exception("The required lattice norm is only implemented for T=L at the moment.") -661 -662 if Zeuthen_flow is not True: -663 raise Exception("The required lattice norm is only implemented for the Zeuthen flow at the moment.") -664 -665 t = (c * L) ** 2 / 8 -666 -667 normdict = {4: 0.012341170468270, -668 6: 0.010162691462430, -669 8: 0.009031614807931, -670 10: 0.008744966371393, -671 12: 0.008650917856809, -672 14: 8.611154391267955E-03, -673 16: 0.008591758449508, -674 20: 0.008575359627103, -675 24: 0.008569387847540, -676 28: 8.566803713382559E-03, -677 32: 0.008565541650006, -678 40: 8.564480684962046E-03, -679 48: 8.564098025073460E-03, -680 64: 8.563853943383087E-03} +@@ -2134,30 +2170,30 @@ postfix of the file to read, e.g. '.gfms.dat' for openQCD-files644def read_gf_coupling(path, prefix, c, dtr_cnfg=1, Zeuthen_flow=True, **kwargs): +645 """Read the gradient flow coupling based on sfqcd gradient flow measurements. See 1607.06423 for details. +646 +647 Note: The current implementation only works for c=0.3 and T=L. The definition of the coupling in 1607.06423 requires projection to topological charge zero which is not done within this function but has to be performed in a separate step. +648 +649 Parameters +650 ---------- +651 path : str +652 path of the measurement files +653 prefix : str +654 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. +655 Ignored if file names are passed explicitly via keyword files. +656 c : double +657 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. +658 dtr_cnfg : int +659 (optional) parameter that specifies the number of measurements +660 between two configs. +661 If it is not set, the distance between two measurements +662 in the file is assumed to be the distance between two configurations. +663 steps : int +664 (optional) Distance between two configurations in units of trajectories / +665 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given +666 r_start : list +667 list which contains the first config to be read for each replicum. +668 r_stop : list +669 list which contains the last config to be read for each replicum. +670 files : list +671 specify the exact files that need to be read +672 from path, practical if e.g. only one replicum is needed +673 names : list +674 Alternative labeling for replicas/ensembles. +675 Has to have the appropriate length. +676 postfix : str +677 postfix of the file to read, e.g. '.gfms.dat' for openQCD-files +678 Zeuthen_flow : bool +679 (optional) If True, the Zeuthen flow is used for the coupling. If False, the Wilson flow is used. +680 """ 681 -682 return t * t * (5 / 3 * plaq - 1 / 12 * C2x1) / normdict[L] +682 if c != 0.3: +683 raise Exception("The required lattice norm is only implemented for c=0.3 at the moment.") +684 +685 plaq = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=6, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) +686 C2x1 = _read_flow_obs(path, prefix, c, dtr_cnfg=dtr_cnfg, version="sfqcd", obspos=7, sum_t=False, Zeuthen_flow=Zeuthen_flow, integer_charge=False, **kwargs) +687 L = plaq.tag["L"] +688 T = plaq.tag["T"] +689 +690 if T != L: +691 raise Exception("The required lattice norm is only implemented for T=L at the moment.") +692 +693 if Zeuthen_flow is not True: +694 raise Exception("The required lattice norm is only implemented for the Zeuthen flow at the moment.") +695 +696 t = (c * L) ** 2 / 8 +697 +698 normdict = {4: 0.012341170468270, +699 6: 0.010162691462430, +700 8: 0.009031614807931, +701 10: 0.008744966371393, +702 12: 0.008650917856809, +703 14: 8.611154391267955E-03, +704 16: 0.008591758449508, +705 20: 0.008575359627103, +706 24: 0.008569387847540, +707 28: 8.566803713382559E-03, +708 32: 0.008565541650006, +709 40: 8.564480684962046E-03, +710 48: 8.564098025073460E-03, +711 64: 8.563853943383087E-03} +712 +713 return t * t * (5 / 3 * plaq - 1 / 12 * C2x1) / normdict[L]
954def qtop_projection(qtop, target=0): -955 """Returns the projection to the topological charge sector defined by target. -956 -957 Parameters -958 ---------- -959 path : Obs -960 Topological charge. -961 target : int -962 Specifies the topological sector to be reweighted to (default 0) -963 -964 Returns -965 ------- -966 reto : Obs -967 projection to the topological charge sector defined by target -968 """ -969 if qtop.reweighted: -970 raise Exception('You can not use a reweighted observable for reweighting!') -971 -972 proj_qtop = [] -973 for n in qtop.deltas: -974 proj_qtop.append(np.array([1 if round(qtop.r_values[n] + q) == target else 0 for q in qtop.deltas[n]])) -975 -976 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) -977 return reto +@@ -2193,62 +2229,62 @@ projection to the topological charge sector defined by target988def qtop_projection(qtop, target=0): + 989 """Returns the projection to the topological charge sector defined by target. + 990 + 991 Parameters + 992 ---------- + 993 path : Obs + 994 Topological charge. + 995 target : int + 996 Specifies the topological sector to be reweighted to (default 0) + 997 + 998 Returns + 999 ------- +1000 reto : Obs +1001 projection to the topological charge sector defined by target +1002 """ +1003 if qtop.reweighted: +1004 raise Exception('You can not use a reweighted observable for reweighting!') +1005 +1006 proj_qtop = [] +1007 for n in qtop.deltas: +1008 proj_qtop.append(np.array([1 if round(qtop.r_values[n] + q) == target else 0 for q in qtop.deltas[n]])) +1009 +1010 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) +1011 return reto
980def read_qtop_sector(path, prefix, c, target=0, **kwargs): - 981 """Constructs reweighting factors to a specified topological sector. - 982 - 983 Parameters - 984 ---------- - 985 path : str - 986 path of the measurement files - 987 prefix : str - 988 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat - 989 c : double - 990 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L - 991 target : int - 992 Specifies the topological sector to be reweighted to (default 0) - 993 dtr_cnfg : int - 994 (optional) parameter that specifies the number of trajectories - 995 between two configs. - 996 if it is not set, the distance between two measurements - 997 in the file is assumed to be the distance between two configurations. - 998 steps : int - 999 (optional) Distance between two configurations in units of trajectories / -1000 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given -1001 version : str -1002 version string of the openQCD (sfqcd) version used to create -1003 the ensemble. Default is 2.0. May also be set to sfqcd. -1004 L : int -1005 spatial length of the lattice in L/a. -1006 HAS to be set if version != sfqcd, since openQCD does not provide -1007 this in the header -1008 r_start : list -1009 offset of the first ensemble, making it easier to match -1010 later on with other Obs -1011 r_stop : list -1012 last configurations that need to be read (per replicum) -1013 files : list -1014 specify the exact files that need to be read -1015 from path, practical if e.g. only one replicum is needed -1016 names : list -1017 Alternative labeling for replicas/ensembles. -1018 Has to have the appropriate length -1019 Zeuthen_flow : bool -1020 (optional) If True, the Zeuthen flow is used for Qtop. Only possible -1021 for version=='sfqcd' If False, the Wilson flow is used. -1022 -1023 Returns -1024 ------- -1025 reto : Obs -1026 projection to the topological charge sector defined by target -1027 """ -1028 -1029 if not isinstance(target, int): -1030 raise Exception("'target' has to be an integer.") -1031 -1032 kwargs['integer_charge'] = True -1033 qtop = read_qtop(path, prefix, c, **kwargs) -1034 -1035 return qtop_projection(qtop, target=target) +@@ -2317,159 +2353,159 @@ projection to the topological charge sector defined by target1014def read_qtop_sector(path, prefix, c, target=0, **kwargs): +1015 """Constructs reweighting factors to a specified topological sector. +1016 +1017 Parameters +1018 ---------- +1019 path : str +1020 path of the measurement files +1021 prefix : str +1022 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat +1023 c : double +1024 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L +1025 target : int +1026 Specifies the topological sector to be reweighted to (default 0) +1027 dtr_cnfg : int +1028 (optional) parameter that specifies the number of trajectories +1029 between two configs. +1030 if it is not set, the distance between two measurements +1031 in the file is assumed to be the distance between two configurations. +1032 steps : int +1033 (optional) Distance between two configurations in units of trajectories / +1034 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given +1035 version : str +1036 version string of the openQCD (sfqcd) version used to create +1037 the ensemble. Default is 2.0. May also be set to sfqcd. +1038 L : int +1039 spatial length of the lattice in L/a. +1040 HAS to be set if version != sfqcd, since openQCD does not provide +1041 this in the header +1042 r_start : list +1043 offset of the first ensemble, making it easier to match +1044 later on with other Obs +1045 r_stop : list +1046 last configurations that need to be read (per replicum) +1047 files : list +1048 specify the exact files that need to be read +1049 from path, practical if e.g. only one replicum is needed +1050 names : list +1051 Alternative labeling for replicas/ensembles. +1052 Has to have the appropriate length +1053 Zeuthen_flow : bool +1054 (optional) If True, the Zeuthen flow is used for Qtop. Only possible +1055 for version=='sfqcd' If False, the Wilson flow is used. +1056 +1057 Returns +1058 ------- +1059 reto : Obs +1060 projection to the topological charge sector defined by target +1061 """ +1062 +1063 if not isinstance(target, int): +1064 raise Exception("'target' has to be an integer.") +1065 +1066 kwargs['integer_charge'] = True +1067 qtop = read_qtop(path, prefix, c, **kwargs) +1068 +1069 return qtop_projection(qtop, target=target)
1038def read_ms5_xsf(path, prefix, qc, corr, sep="r", **kwargs): -1039 """ -1040 Read data from files in the specified directory with the specified prefix and quark combination extension, and return a `Corr` object containing the data. -1041 -1042 Parameters -1043 ---------- -1044 path : str -1045 The directory to search for the files in. -1046 prefix : str -1047 The prefix to match the files against. -1048 qc : str -1049 The quark combination extension to match the files against. -1050 corr : str -1051 The correlator to extract data for. -1052 sep : str, optional -1053 The separator to use when parsing the replika names. -1054 **kwargs -1055 Additional keyword arguments. The following keyword arguments are recognized: -1056 -1057 - names (List[str]): A list of names to use for the replicas. -1058 -1059 Returns -1060 ------- -1061 Corr -1062 A complex valued `Corr` object containing the data read from the files. In case of boudary to bulk correlators. -1063 or -1064 CObs -1065 A complex valued `CObs` object containing the data read from the files. In case of boudary to boundary correlators. -1066 -1067 -1068 Raises -1069 ------ -1070 FileNotFoundError -1071 If no files matching the specified prefix and quark combination extension are found in the specified directory. -1072 IOError -1073 If there is an error reading a file. -1074 struct.error -1075 If there is an error unpacking binary data. -1076 """ -1077 -1078 # found = [] -1079 files = [] -1080 names = [] -1081 -1082 # test if the input is correct -1083 if qc not in ['dd', 'ud', 'du', 'uu']: -1084 raise Exception("Unknown quark conbination!") -1085 -1086 if corr not in ["gS", "gP", "gA", "gV", "gVt", "lA", "lV", "lVt", "lT", "lTt", "g1", "l1"]: -1087 raise Exception("Unknown correlator!") -1088 -1089 if "files" in kwargs: -1090 known_files = kwargs.get("files") -1091 else: -1092 known_files = [] -1093 files = _find_files(path, prefix, "ms5_xsf_" + qc, "dat", known_files=known_files) -1094 -1095 if "names" in kwargs: -1096 names = kwargs.get("names") -1097 else: -1098 for f in files: -1099 if not sep == "": -1100 se = f.split(".")[0] -1101 for s in f.split(".")[1:-2]: -1102 se += "." + s -1103 names.append(se.split(sep)[0] + "|r" + se.split(sep)[1]) -1104 else: -1105 names.append(prefix) -1106 -1107 names = sorted(names) -1108 files = sorted(files) -1109 -1110 cnfgs = [] -1111 realsamples = [] -1112 imagsamples = [] -1113 repnum = 0 -1114 for file in files: -1115 with open(path + "/" + file, "rb") as fp: -1116 -1117 t = fp.read(8) -1118 kappa = struct.unpack('d', t)[0] -1119 t = fp.read(8) -1120 csw = struct.unpack('d', t)[0] -1121 t = fp.read(8) -1122 dF = struct.unpack('d', t)[0] -1123 t = fp.read(8) -1124 zF = struct.unpack('d', t)[0] -1125 -1126 t = fp.read(4) -1127 tmax = struct.unpack('i', t)[0] -1128 t = fp.read(4) -1129 bnd = struct.unpack('i', t)[0] -1130 -1131 placesBI = ["gS", "gP", -1132 "gA", "gV", -1133 "gVt", "lA", -1134 "lV", "lVt", -1135 "lT", "lTt"] -1136 placesBB = ["g1", "l1"] -1137 -1138 # the chunks have the following structure: -1139 # confignumber, 10x timedependent complex correlators as doubles, 2x timeindependent complex correlators as doubles +1072def read_ms5_xsf(path, prefix, qc, corr, sep="r", **kwargs): +1073 """ +1074 Read data from files in the specified directory with the specified prefix and quark combination extension, and return a `Corr` object containing the data. +1075 +1076 Parameters +1077 ---------- +1078 path : str +1079 The directory to search for the files in. +1080 prefix : str +1081 The prefix to match the files against. +1082 qc : str +1083 The quark combination extension to match the files against. +1084 corr : str +1085 The correlator to extract data for. +1086 sep : str, optional +1087 The separator to use when parsing the replika names. +1088 **kwargs +1089 Additional keyword arguments. The following keyword arguments are recognized: +1090 +1091 - names (List[str]): A list of names to use for the replicas. +1092 +1093 Returns +1094 ------- +1095 Corr +1096 A complex valued `Corr` object containing the data read from the files. In case of boudary to bulk correlators. +1097 or +1098 CObs +1099 A complex valued `CObs` object containing the data read from the files. In case of boudary to boundary correlators. +1100 +1101 +1102 Raises +1103 ------ +1104 FileNotFoundError +1105 If no files matching the specified prefix and quark combination extension are found in the specified directory. +1106 IOError +1107 If there is an error reading a file. +1108 struct.error +1109 If there is an error unpacking binary data. +1110 """ +1111 +1112 # found = [] +1113 files = [] +1114 names = [] +1115 +1116 # test if the input is correct +1117 if qc not in ['dd', 'ud', 'du', 'uu']: +1118 raise Exception("Unknown quark conbination!") +1119 +1120 if corr not in ["gS", "gP", "gA", "gV", "gVt", "lA", "lV", "lVt", "lT", "lTt", "g1", "l1"]: +1121 raise Exception("Unknown correlator!") +1122 +1123 if "files" in kwargs: +1124 known_files = kwargs.get("files") +1125 else: +1126 known_files = [] +1127 files = _find_files(path, prefix, "ms5_xsf_" + qc, "dat", known_files=known_files) +1128 +1129 if "names" in kwargs: +1130 names = kwargs.get("names") +1131 else: +1132 for f in files: +1133 if not sep == "": +1134 se = f.split(".")[0] +1135 for s in f.split(".")[1:-2]: +1136 se += "." + s +1137 names.append(se.split(sep)[0] + "|r" + se.split(sep)[1]) +1138 else: +1139 names.append(prefix) 1140 -1141 chunksize = 4 + (8 * 2 * tmax * 10) + (8 * 2 * 2) -1142 packstr = '=i' + ('d' * 2 * tmax * 10) + ('d' * 2 * 2) -1143 cnfgs.append([]) -1144 realsamples.append([]) -1145 imagsamples.append([]) -1146 for t in range(tmax): -1147 realsamples[repnum].append([]) -1148 imagsamples[repnum].append([]) -1149 -1150 while True: -1151 cnfgt = fp.read(chunksize) -1152 if not cnfgt: -1153 break -1154 asascii = struct.unpack(packstr, cnfgt) -1155 cnfg = asascii[0] -1156 cnfgs[repnum].append(cnfg) -1157 -1158 if corr not in placesBB: -1159 tmpcorr = asascii[1 + 2 * tmax * placesBI.index(corr):1 + 2 * tmax * placesBI.index(corr) + 2 * tmax] -1160 else: -1161 tmpcorr = asascii[1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr):1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr) + 2] -1162 -1163 corrres = [[], []] -1164 for i in range(len(tmpcorr)): -1165 corrres[i % 2].append(tmpcorr[i]) -1166 for t in range(int(len(tmpcorr) / 2)): -1167 realsamples[repnum][t].append(corrres[0][t]) -1168 for t in range(int(len(tmpcorr) / 2)): -1169 imagsamples[repnum][t].append(corrres[1][t]) -1170 repnum += 1 +1141 names = sorted(names) +1142 files = sorted(files) +1143 +1144 cnfgs = [] +1145 realsamples = [] +1146 imagsamples = [] +1147 repnum = 0 +1148 for file in files: +1149 with open(path + "/" + file, "rb") as fp: +1150 +1151 t = fp.read(8) +1152 kappa = struct.unpack('d', t)[0] +1153 t = fp.read(8) +1154 csw = struct.unpack('d', t)[0] +1155 t = fp.read(8) +1156 dF = struct.unpack('d', t)[0] +1157 t = fp.read(8) +1158 zF = struct.unpack('d', t)[0] +1159 +1160 t = fp.read(4) +1161 tmax = struct.unpack('i', t)[0] +1162 t = fp.read(4) +1163 bnd = struct.unpack('i', t)[0] +1164 +1165 placesBI = ["gS", "gP", +1166 "gA", "gV", +1167 "gVt", "lA", +1168 "lV", "lVt", +1169 "lT", "lTt"] +1170 placesBB = ["g1", "l1"] 1171 -1172 s = "Read correlator " + corr + " from " + str(repnum) + " replika with " + str(len(realsamples[0][t])) -1173 for rep in range(1, repnum): -1174 s += ", " + str(len(realsamples[rep][t])) -1175 s += " samples" -1176 print(s) -1177 print("Asserted run parameters:\n T:", tmax, "kappa:", kappa, "csw:", csw, "dF:", dF, "zF:", zF, "bnd:", bnd) -1178 -1179 # we have the data now... but we need to re format the whole thing and put it into Corr objects. -1180 -1181 compObs = [] -1182 -1183 for t in range(int(len(tmpcorr) / 2)): -1184 compObs.append(CObs(Obs([realsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs), -1185 Obs([imagsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs))) -1186 -1187 if len(compObs) == 1: -1188 return compObs[0] -1189 else: -1190 return Corr(compObs) +1172 # the chunks have the following structure: +1173 # confignumber, 10x timedependent complex correlators as doubles, 2x timeindependent complex correlators as doubles +1174 +1175 chunksize = 4 + (8 * 2 * tmax * 10) + (8 * 2 * 2) +1176 packstr = '=i' + ('d' * 2 * tmax * 10) + ('d' * 2 * 2) +1177 cnfgs.append([]) +1178 realsamples.append([]) +1179 imagsamples.append([]) +1180 for t in range(tmax): +1181 realsamples[repnum].append([]) +1182 imagsamples[repnum].append([]) +1183 +1184 while True: +1185 cnfgt = fp.read(chunksize) +1186 if not cnfgt: +1187 break +1188 asascii = struct.unpack(packstr, cnfgt) +1189 cnfg = asascii[0] +1190 cnfgs[repnum].append(cnfg) +1191 +1192 if corr not in placesBB: +1193 tmpcorr = asascii[1 + 2 * tmax * placesBI.index(corr):1 + 2 * tmax * placesBI.index(corr) + 2 * tmax] +1194 else: +1195 tmpcorr = asascii[1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr):1 + 2 * tmax * len(placesBI) + 2 * placesBB.index(corr) + 2] +1196 +1197 corrres = [[], []] +1198 for i in range(len(tmpcorr)): +1199 corrres[i % 2].append(tmpcorr[i]) +1200 for t in range(int(len(tmpcorr) / 2)): +1201 realsamples[repnum][t].append(corrres[0][t]) +1202 for t in range(int(len(tmpcorr) / 2)): +1203 imagsamples[repnum][t].append(corrres[1][t]) +1204 repnum += 1 +1205 +1206 s = "Read correlator " + corr + " from " + str(repnum) + " replika with " + str(len(realsamples[0][t])) +1207 for rep in range(1, repnum): +1208 s += ", " + str(len(realsamples[rep][t])) +1209 s += " samples" +1210 print(s) +1211 print("Asserted run parameters:\n T:", tmax, "kappa:", kappa, "csw:", csw, "dF:", dF, "zF:", zF, "bnd:", bnd) +1212 +1213 # we have the data now... but we need to re format the whole thing and put it into Corr objects. +1214 +1215 compObs = [] +1216 +1217 for t in range(int(len(tmpcorr) / 2)): +1218 compObs.append(CObs(Obs([realsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs), +1219 Obs([imagsamples[rep][t] for rep in range(repnum)], names=names, idl=cnfgs))) +1220 +1221 if len(compObs) == 1: +1222 return compObs[0] +1223 else: +1224 return Corr(compObs)