pyerrors.input.json
1import rapidjson as json 2import gzip 3import getpass 4import socket 5import datetime 6import platform 7import warnings 8import re 9import numpy as np 10from ..obs import Obs 11from ..covobs import Covobs 12from ..correlators import Corr 13from ..misc import _assert_equal_properties 14from .. import version as pyerrorsversion 15 16 17def create_json_string(ol, description='', indent=1): 18 """Generate the string for the export of a list of Obs or structures containing Obs 19 to a .json(.gz) file 20 21 Parameters 22 ---------- 23 ol : list 24 List of objects that will be exported. At the moment, these objects can be 25 either of: Obs, list, numpy.ndarray, Corr. 26 All Obs inside a structure have to be defined on the same set of configurations. 27 description : str 28 Optional string that describes the contents of the json file. 29 indent : int 30 Specify the indentation level of the json file. None or 0 is permissible and 31 saves disk space. 32 33 Returns 34 ------- 35 json_string : str 36 String for export to .json(.gz) file 37 """ 38 39 def _gen_data_d_from_list(ol): 40 dl = [] 41 No = len(ol) 42 for name in ol[0].mc_names: 43 ed = {} 44 ed['id'] = name 45 ed['replica'] = [] 46 for r_name in ol[0].e_content[name]: 47 rd = {} 48 rd['name'] = r_name 49 rd['deltas'] = [] 50 offsets = [o.r_values[r_name] - o.value for o in ol] 51 deltas = np.column_stack([ol[oi].deltas[r_name] + offsets[oi] for oi in range(No)]) 52 for i in range(len(ol[0].idl[r_name])): 53 rd['deltas'].append([ol[0].idl[r_name][i]]) 54 rd['deltas'][-1] += deltas[i].tolist() 55 ed['replica'].append(rd) 56 dl.append(ed) 57 return dl 58 59 def _gen_cdata_d_from_list(ol): 60 dl = [] 61 for name in ol[0].cov_names: 62 ed = {} 63 ed['id'] = name 64 ed['layout'] = str(ol[0].covobs[name].cov.shape).lstrip('(').rstrip(')').rstrip(',') 65 ed['cov'] = list(np.ravel(ol[0].covobs[name].cov)) 66 ncov = ol[0].covobs[name].cov.shape[0] 67 ed['grad'] = [] 68 for i in range(ncov): 69 ed['grad'].append([]) 70 for o in ol: 71 ed['grad'][-1].append(o.covobs[name].grad[i][0]) 72 dl.append(ed) 73 return dl 74 75 def write_Obs_to_dict(o): 76 d = {} 77 d['type'] = 'Obs' 78 d['layout'] = '1' 79 if o.tag: 80 d['tag'] = [o.tag] 81 if o.reweighted: 82 d['reweighted'] = o.reweighted 83 d['value'] = [o.value] 84 data = _gen_data_d_from_list([o]) 85 if len(data) > 0: 86 d['data'] = data 87 cdata = _gen_cdata_d_from_list([o]) 88 if len(cdata) > 0: 89 d['cdata'] = cdata 90 return d 91 92 def write_List_to_dict(ol): 93 _assert_equal_properties(ol) 94 d = {} 95 d['type'] = 'List' 96 d['layout'] = '%d' % len(ol) 97 taglist = [o.tag for o in ol] 98 if np.any([tag is not None for tag in taglist]): 99 d['tag'] = taglist 100 if ol[0].reweighted: 101 d['reweighted'] = ol[0].reweighted 102 d['value'] = [o.value for o in ol] 103 data = _gen_data_d_from_list(ol) 104 if len(data) > 0: 105 d['data'] = data 106 cdata = _gen_cdata_d_from_list(ol) 107 if len(cdata) > 0: 108 d['cdata'] = cdata 109 return d 110 111 def write_Array_to_dict(oa): 112 ol = np.ravel(oa) 113 _assert_equal_properties(ol) 114 d = {} 115 d['type'] = 'Array' 116 d['layout'] = str(oa.shape).lstrip('(').rstrip(')').rstrip(',') 117 taglist = [o.tag for o in ol] 118 if np.any([tag is not None for tag in taglist]): 119 d['tag'] = taglist 120 if ol[0].reweighted: 121 d['reweighted'] = ol[0].reweighted 122 d['value'] = [o.value for o in ol] 123 data = _gen_data_d_from_list(ol) 124 if len(data) > 0: 125 d['data'] = data 126 cdata = _gen_cdata_d_from_list(ol) 127 if len(cdata) > 0: 128 d['cdata'] = cdata 129 return d 130 131 def _nan_Obs_like(obs): 132 samples = [] 133 names = [] 134 idl = [] 135 for key, value in obs.idl.items(): 136 samples.append([np.nan] * len(value)) 137 names.append(key) 138 idl.append(value) 139 my_obs = Obs(samples, names, idl) 140 my_obs._covobs = obs._covobs 141 for name in obs._covobs: 142 my_obs.names.append(name) 143 my_obs.reweighted = obs.reweighted 144 return my_obs 145 146 def write_Corr_to_dict(my_corr): 147 first_not_none = next(i for i, j in enumerate(my_corr.content) if np.all(j)) 148 dummy_array = np.empty((my_corr.N, my_corr.N), dtype=object) 149 dummy_array[:] = _nan_Obs_like(my_corr.content[first_not_none].ravel()[0]) 150 content = [o if o is not None else dummy_array for o in my_corr.content] 151 dat = write_Array_to_dict(np.array(content, dtype=object)) 152 dat['type'] = 'Corr' 153 corr_meta_data = str(my_corr.tag) 154 if 'tag' in dat.keys(): 155 dat['tag'].append(corr_meta_data) 156 else: 157 dat['tag'] = [corr_meta_data] 158 taglist = dat['tag'] 159 dat['tag'] = {} # tag is now a dictionary, that contains the previous taglist in the key "tag" 160 dat['tag']['tag'] = taglist 161 if my_corr.prange is not None: 162 dat['tag']['prange'] = my_corr.prange 163 return dat 164 165 if not isinstance(ol, list): 166 ol = [ol] 167 168 d = {} 169 d['program'] = 'pyerrors %s' % (pyerrorsversion.__version__) 170 d['version'] = '1.1' 171 d['who'] = getpass.getuser() 172 d['date'] = datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S %z') 173 d['host'] = socket.gethostname() + ', ' + platform.platform() 174 175 if description: 176 d['description'] = description 177 178 d['obsdata'] = [] 179 for io in ol: 180 if isinstance(io, Obs): 181 d['obsdata'].append(write_Obs_to_dict(io)) 182 elif isinstance(io, list): 183 d['obsdata'].append(write_List_to_dict(io)) 184 elif isinstance(io, np.ndarray): 185 d['obsdata'].append(write_Array_to_dict(io)) 186 elif isinstance(io, Corr): 187 d['obsdata'].append(write_Corr_to_dict(io)) 188 else: 189 raise Exception("Unkown datatype.") 190 191 def _jsonifier(obj): 192 if isinstance(obj, dict): 193 result = {} 194 for key in obj: 195 if key is True: 196 result['true'] = obj[key] 197 elif key is False: 198 result['false'] = obj[key] 199 elif key is None: 200 result['null'] = obj[key] 201 elif isinstance(key, (int, float, np.floating, np.integer)): 202 result[str(key)] = obj[key] 203 else: 204 raise TypeError('keys must be str, int, float, bool or None') 205 return result 206 elif isinstance(obj, np.integer): 207 return int(obj) 208 elif isinstance(obj, np.floating): 209 return float(obj) 210 else: 211 raise ValueError('%r is not JSON serializable' % (obj,)) 212 213 if indent: 214 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_SINGLE_LINE_ARRAY) 215 else: 216 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_COMPACT) 217 218 219def dump_to_json(ol, fname, description='', indent=1, gz=True): 220 """Export a list of Obs or structures containing Obs to a .json(.gz) file. 221 Dict keys that are not JSON-serializable such as floats are converted to strings. 222 223 Parameters 224 ---------- 225 ol : list 226 List of objects that will be exported. At the moment, these objects can be 227 either of: Obs, list, numpy.ndarray, Corr. 228 All Obs inside a structure have to be defined on the same set of configurations. 229 fname : str 230 Filename of the output file. 231 description : str 232 Optional string that describes the contents of the json file. 233 indent : int 234 Specify the indentation level of the json file. None or 0 is permissible and 235 saves disk space. 236 gz : bool 237 If True, the output is a gzipped json. If False, the output is a json file. 238 239 Returns 240 ------- 241 Null 242 """ 243 244 jsonstring = create_json_string(ol, description, indent) 245 246 if not fname.endswith('.json') and not fname.endswith('.gz'): 247 fname += '.json' 248 249 if gz: 250 if not fname.endswith('.gz'): 251 fname += '.gz' 252 253 fp = gzip.open(fname, 'wb') 254 fp.write(jsonstring.encode('utf-8')) 255 else: 256 fp = open(fname, 'w', encoding='utf-8') 257 fp.write(jsonstring) 258 fp.close() 259 260 261def _parse_json_dict(json_dict, verbose=True, full_output=False): 262 """Reconstruct a list of Obs or structures containing Obs from a dict that 263 was built out of a json string. 264 265 The following structures are supported: Obs, list, numpy.ndarray, Corr 266 If the list contains only one element, it is unpacked from the list. 267 268 Parameters 269 ---------- 270 json_string : str 271 json string containing the data. 272 verbose : bool 273 Print additional information that was written to the file. 274 full_output : bool 275 If True, a dict containing auxiliary information and the data is returned. 276 If False, only the data is returned. 277 278 Returns 279 ------- 280 result : list[Obs] 281 reconstructed list of observables from the json string 282 or 283 result : Obs 284 only one observable if the list only has one entry 285 or 286 result : dict 287 if full_output=True 288 """ 289 290 def _gen_obsd_from_datad(d): 291 retd = {} 292 if d: 293 retd['names'] = [] 294 retd['idl'] = [] 295 retd['deltas'] = [] 296 for ens in d: 297 for rep in ens['replica']: 298 rep_name = rep['name'] 299 if len(rep_name) > len(ens["id"]): 300 if rep_name[len(ens["id"])] != "|": 301 tmp_list = list(rep_name) 302 tmp_list = tmp_list[:len(ens["id"])] + ["|"] + tmp_list[len(ens["id"]):] 303 rep_name = ''.join(tmp_list) 304 retd['names'].append(rep_name) 305 retd['idl'].append([di[0] for di in rep['deltas']]) 306 retd['deltas'].append(np.array([di[1:] for di in rep['deltas']])) 307 return retd 308 309 def _gen_covobsd_from_cdatad(d): 310 retd = {} 311 for ens in d: 312 retl = [] 313 name = ens['id'] 314 layouts = ens.get('layout', '1').strip() 315 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] 316 cov = np.reshape(ens['cov'], layout) 317 grad = ens['grad'] 318 nobs = len(grad[0]) 319 for i in range(nobs): 320 retl.append({'name': name, 'cov': cov, 'grad': [g[i] for g in grad]}) 321 retd[name] = retl 322 return retd 323 324 def get_Obs_from_dict(o): 325 layouts = o.get('layout', '1').strip() 326 if layouts != '1': 327 raise Exception("layout is %s has to be 1 for type Obs." % (layouts), RuntimeWarning) 328 329 values = o['value'] 330 od = _gen_obsd_from_datad(o.get('data', {})) 331 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) 332 333 if od: 334 ret = Obs([[ddi[0] + values[0] for ddi in di] for di in od['deltas']], od['names'], idl=od['idl']) 335 ret._value = values[0] 336 else: 337 ret = Obs([], [], means=[]) 338 ret._value = values[0] 339 for name in cd: 340 co = cd[name][0] 341 ret._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) 342 ret.names.append(co['name']) 343 344 ret.reweighted = o.get('reweighted', False) 345 ret.tag = o.get('tag', [None])[0] 346 return ret 347 348 def get_List_from_dict(o): 349 layouts = o.get('layout', '1').strip() 350 layout = int(layouts) 351 values = o['value'] 352 od = _gen_obsd_from_datad(o.get('data', {})) 353 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) 354 355 ret = [] 356 taglist = o.get('tag', layout * [None]) 357 for i in range(layout): 358 if od: 359 ret.append(Obs([list(di[:, i] + values[i]) for di in od['deltas']], od['names'], idl=od['idl'])) 360 ret[-1]._value = values[i] 361 else: 362 ret.append(Obs([], [], means=[])) 363 ret[-1]._value = values[i] 364 print('Created Obs with means= ', values[i]) 365 for name in cd: 366 co = cd[name][i] 367 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) 368 ret[-1].names.append(co['name']) 369 370 ret[-1].reweighted = o.get('reweighted', False) 371 ret[-1].tag = taglist[i] 372 return ret 373 374 def get_Array_from_dict(o): 375 layouts = o.get('layout', '1').strip() 376 layout = [int(ls.strip()) for ls in layouts.split(',') if len(ls) > 0] 377 N = np.prod(layout) 378 values = o['value'] 379 od = _gen_obsd_from_datad(o.get('data', {})) 380 cd = _gen_covobsd_from_cdatad(o.get('cdata', {})) 381 382 ret = [] 383 taglist = o.get('tag', N * [None]) 384 for i in range(N): 385 if od: 386 ret.append(Obs([di[:, i] + values[i] for di in od['deltas']], od['names'], idl=od['idl'])) 387 ret[-1]._value = values[i] 388 else: 389 ret.append(Obs([], [], means=[])) 390 ret[-1]._value = values[i] 391 for name in cd: 392 co = cd[name][i] 393 ret[-1]._covobs[name] = Covobs(None, co['cov'], co['name'], grad=co['grad']) 394 ret[-1].names.append(co['name']) 395 ret[-1].reweighted = o.get('reweighted', False) 396 ret[-1].tag = taglist[i] 397 return np.reshape(ret, layout) 398 399 def get_Corr_from_dict(o): 400 if isinstance(o.get('tag'), list): # supports the old way 401 taglist = o.get('tag') # This had to be modified to get the taglist from the dictionary 402 temp_prange = None 403 elif isinstance(o.get('tag'), dict): 404 tagdic = o.get('tag') 405 taglist = tagdic['tag'] 406 if 'prange' in tagdic: 407 temp_prange = tagdic['prange'] 408 else: 409 temp_prange = None 410 else: 411 raise Exception("The tag is not a list or dict") 412 413 corr_tag = taglist[-1] 414 tmp_o = o 415 tmp_o['tag'] = taglist[:-1] 416 if len(tmp_o['tag']) == 0: 417 del tmp_o['tag'] 418 dat = get_Array_from_dict(tmp_o) 419 my_corr = Corr([None if np.isnan(o.ravel()[0].value) else o for o in list(dat)]) 420 if corr_tag != 'None': 421 my_corr.tag = corr_tag 422 423 my_corr.prange = temp_prange 424 return my_corr 425 426 prog = json_dict.get('program', '') 427 version = json_dict.get('version', '') 428 who = json_dict.get('who', '') 429 date = json_dict.get('date', '') 430 host = json_dict.get('host', '') 431 if prog and verbose: 432 print('Data has been written using %s.' % (prog)) 433 if version and verbose: 434 print('Format version %s' % (version)) 435 if np.any([who, date, host] and verbose): 436 print('Written by %s on %s on host %s' % (who, date, host)) 437 description = json_dict.get('description', '') 438 if description and verbose: 439 print() 440 print('Description: ', description) 441 obsdata = json_dict['obsdata'] 442 ol = [] 443 for io in obsdata: 444 if io['type'] == 'Obs': 445 ol.append(get_Obs_from_dict(io)) 446 elif io['type'] == 'List': 447 ol.append(get_List_from_dict(io)) 448 elif io['type'] == 'Array': 449 ol.append(get_Array_from_dict(io)) 450 elif io['type'] == 'Corr': 451 ol.append(get_Corr_from_dict(io)) 452 else: 453 raise Exception("Unknown datatype.") 454 455 if full_output: 456 retd = {} 457 retd['program'] = prog 458 retd['version'] = version 459 retd['who'] = who 460 retd['date'] = date 461 retd['host'] = host 462 retd['description'] = description 463 retd['obsdata'] = ol 464 465 return retd 466 else: 467 if len(obsdata) == 1: 468 ol = ol[0] 469 470 return ol 471 472 473def import_json_string(json_string, verbose=True, full_output=False): 474 """Reconstruct a list of Obs or structures containing Obs from a json string. 475 476 The following structures are supported: Obs, list, numpy.ndarray, Corr 477 If the list contains only one element, it is unpacked from the list. 478 479 Parameters 480 ---------- 481 json_string : str 482 json string containing the data. 483 verbose : bool 484 Print additional information that was written to the file. 485 full_output : bool 486 If True, a dict containing auxiliary information and the data is returned. 487 If False, only the data is returned. 488 489 Returns 490 ------- 491 result : list[Obs] 492 reconstructed list of observables from the json string 493 or 494 result : Obs 495 only one observable if the list only has one entry 496 or 497 result : dict 498 if full_output=True 499 """ 500 return _parse_json_dict(json.loads(json_string), verbose, full_output) 501 502 503def load_json(fname, verbose=True, gz=True, full_output=False): 504 """Import a list of Obs or structures containing Obs from a .json(.gz) file. 505 506 The following structures are supported: Obs, list, numpy.ndarray, Corr 507 If the list contains only one element, it is unpacked from the list. 508 509 Parameters 510 ---------- 511 fname : str 512 Filename of the input file. 513 verbose : bool 514 Print additional information that was written to the file. 515 gz : bool 516 If True, assumes that data is gzipped. If False, assumes JSON file. 517 full_output : bool 518 If True, a dict containing auxiliary information and the data is returned. 519 If False, only the data is returned. 520 521 Returns 522 ------- 523 result : list[Obs] 524 reconstructed list of observables from the json string 525 or 526 result : Obs 527 only one observable if the list only has one entry 528 or 529 result : dict 530 if full_output=True 531 """ 532 if not fname.endswith('.json') and not fname.endswith('.gz'): 533 fname += '.json' 534 if gz: 535 if not fname.endswith('.gz'): 536 fname += '.gz' 537 with gzip.open(fname, 'r') as fin: 538 d = json.load(fin) 539 else: 540 if fname.endswith('.gz'): 541 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) 542 with open(fname, 'r', encoding='utf-8') as fin: 543 d = json.loads(fin.read()) 544 545 return _parse_json_dict(d, verbose, full_output) 546 547 548def _ol_from_dict(ind, reps='DICTOBS'): 549 """Convert a dictionary of Obs objects to a list and a dictionary that contains 550 placeholders instead of the Obs objects. 551 552 Parameters 553 ---------- 554 ind : dict 555 Dict of JSON valid structures and objects that will be exported. 556 At the moment, these object can be either of: Obs, list, numpy.ndarray, Corr. 557 All Obs inside a structure have to be defined on the same set of configurations. 558 reps : str 559 Specify the structure of the placeholder in exported dict to be reps[0-9]+. 560 """ 561 562 obstypes = (Obs, Corr, np.ndarray) 563 564 if not reps.isalnum(): 565 raise Exception('Placeholder string has to be alphanumeric!') 566 ol = [] 567 counter = 0 568 569 def dict_replace_obs(d): 570 nonlocal ol 571 nonlocal counter 572 x = {} 573 for k, v in d.items(): 574 if isinstance(v, dict): 575 v = dict_replace_obs(v) 576 elif isinstance(v, list) and all([isinstance(o, Obs) for o in v]): 577 v = obslist_replace_obs(v) 578 elif isinstance(v, list): 579 v = list_replace_obs(v) 580 elif isinstance(v, obstypes): 581 ol.append(v) 582 v = reps + '%d' % (counter) 583 counter += 1 584 elif isinstance(v, str): 585 if bool(re.match(r'%s[0-9]+' % (reps), v)): 586 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be safely exported.' % (v, reps)) 587 x[k] = v 588 return x 589 590 def list_replace_obs(li): 591 nonlocal ol 592 nonlocal counter 593 x = [] 594 for e in li: 595 if isinstance(e, list): 596 e = list_replace_obs(e) 597 elif isinstance(e, list) and all([isinstance(o, Obs) for o in e]): 598 e = obslist_replace_obs(e) 599 elif isinstance(e, dict): 600 e = dict_replace_obs(e) 601 elif isinstance(e, obstypes): 602 ol.append(e) 603 e = reps + '%d' % (counter) 604 counter += 1 605 elif isinstance(e, str): 606 if bool(re.match(r'%s[0-9]+' % (reps), e)): 607 raise Exception('Dict contains string %s that matches the placeholder! %s Cannot be safely exported.' % (e, reps)) 608 x.append(e) 609 return x 610 611 def obslist_replace_obs(li): 612 nonlocal ol 613 nonlocal counter 614 il = [] 615 for e in li: 616 il.append(e) 617 618 ol.append(il) 619 x = reps + '%d' % (counter) 620 counter += 1 621 return x 622 623 nd = dict_replace_obs(ind) 624 625 return ol, nd 626 627 628def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): 629 """Export a dict of Obs or structures containing Obs to a .json(.gz) file 630 631 Parameters 632 ---------- 633 od : dict 634 Dict of JSON valid structures and objects that will be exported. 635 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. 636 All Obs inside a structure have to be defined on the same set of configurations. 637 fname : str 638 Filename of the output file. 639 description : str 640 Optional string that describes the contents of the json file. 641 indent : int 642 Specify the indentation level of the json file. None or 0 is permissible and 643 saves disk space. 644 reps : str 645 Specify the structure of the placeholder in exported dict to be reps[0-9]+. 646 gz : bool 647 If True, the output is a gzipped json. If False, the output is a json file. 648 649 Returns 650 ------- 651 None 652 """ 653 654 if not isinstance(od, dict): 655 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') 656 657 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' 658 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' 659 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' 660 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') 661 662 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} 663 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) 664 665 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz) 666 667 668def _od_from_list_and_dict(ol, ind, reps='DICTOBS'): 669 """Parse a list of Obs or structures containing Obs and an accompanying 670 dict, where the structures have been replaced by placeholders to a 671 dict that contains the structures. 672 673 The following structures are supported: Obs, list, numpy.ndarray, Corr 674 675 Parameters 676 ---------- 677 ol : list 678 List of objects - 679 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. 680 All Obs inside a structure have to be defined on the same set of configurations. 681 ind : dict 682 Dict that defines the structure of the resulting dict and contains placeholders 683 reps : str 684 Specify the structure of the placeholder in imported dict to be reps[0-9]+. 685 """ 686 if not reps.isalnum(): 687 raise Exception('Placeholder string has to be alphanumeric!') 688 689 counter = 0 690 691 def dict_replace_string(d): 692 nonlocal counter 693 nonlocal ol 694 x = {} 695 for k, v in d.items(): 696 if isinstance(v, dict): 697 v = dict_replace_string(v) 698 elif isinstance(v, list): 699 v = list_replace_string(v) 700 elif isinstance(v, str) and bool(re.match(r'%s[0-9]+' % (reps), v)): 701 index = int(v[len(reps):]) 702 v = ol[index] 703 counter += 1 704 x[k] = v 705 return x 706 707 def list_replace_string(li): 708 nonlocal counter 709 nonlocal ol 710 x = [] 711 for e in li: 712 if isinstance(e, list): 713 e = list_replace_string(e) 714 elif isinstance(e, dict): 715 e = dict_replace_string(e) 716 elif isinstance(e, str) and bool(re.match(r'%s[0-9]+' % (reps), e)): 717 index = int(e[len(reps):]) 718 e = ol[index] 719 counter += 1 720 x.append(e) 721 return x 722 723 nd = dict_replace_string(ind) 724 725 if counter == 0: 726 raise Exception('No placeholder has been replaced! Check if reps is set correctly.') 727 728 return nd 729 730 731def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): 732 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. 733 734 The following structures are supported: Obs, list, numpy.ndarray, Corr 735 736 Parameters 737 ---------- 738 fname : str 739 Filename of the input file. 740 verbose : bool 741 Print additional information that was written to the file. 742 gz : bool 743 If True, assumes that data is gzipped. If False, assumes JSON file. 744 full_output : bool 745 If True, a dict containing auxiliary information and the data is returned. 746 If False, only the data is returned. 747 reps : str 748 Specify the structure of the placeholder in imported dict to be reps[0-9]+. 749 750 Returns 751 ------- 752 data : Obs / list / Corr 753 Read data 754 or 755 data : dict 756 Read data and meta-data 757 """ 758 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) 759 description = indata['description']['description'] 760 indict = indata['description']['OBSDICT'] 761 ol = indata['obsdata'] 762 od = _od_from_list_and_dict(ol, indict, reps=reps) 763 764 if full_output: 765 indata['description'] = description 766 indata['obsdata'] = od 767 return indata 768 else: 769 return od
18def create_json_string(ol, description='', indent=1): 19 """Generate the string for the export of a list of Obs or structures containing Obs 20 to a .json(.gz) file 21 22 Parameters 23 ---------- 24 ol : list 25 List of objects that will be exported. At the moment, these objects can be 26 either of: Obs, list, numpy.ndarray, Corr. 27 All Obs inside a structure have to be defined on the same set of configurations. 28 description : str 29 Optional string that describes the contents of the json file. 30 indent : int 31 Specify the indentation level of the json file. None or 0 is permissible and 32 saves disk space. 33 34 Returns 35 ------- 36 json_string : str 37 String for export to .json(.gz) file 38 """ 39 40 def _gen_data_d_from_list(ol): 41 dl = [] 42 No = len(ol) 43 for name in ol[0].mc_names: 44 ed = {} 45 ed['id'] = name 46 ed['replica'] = [] 47 for r_name in ol[0].e_content[name]: 48 rd = {} 49 rd['name'] = r_name 50 rd['deltas'] = [] 51 offsets = [o.r_values[r_name] - o.value for o in ol] 52 deltas = np.column_stack([ol[oi].deltas[r_name] + offsets[oi] for oi in range(No)]) 53 for i in range(len(ol[0].idl[r_name])): 54 rd['deltas'].append([ol[0].idl[r_name][i]]) 55 rd['deltas'][-1] += deltas[i].tolist() 56 ed['replica'].append(rd) 57 dl.append(ed) 58 return dl 59 60 def _gen_cdata_d_from_list(ol): 61 dl = [] 62 for name in ol[0].cov_names: 63 ed = {} 64 ed['id'] = name 65 ed['layout'] = str(ol[0].covobs[name].cov.shape).lstrip('(').rstrip(')').rstrip(',') 66 ed['cov'] = list(np.ravel(ol[0].covobs[name].cov)) 67 ncov = ol[0].covobs[name].cov.shape[0] 68 ed['grad'] = [] 69 for i in range(ncov): 70 ed['grad'].append([]) 71 for o in ol: 72 ed['grad'][-1].append(o.covobs[name].grad[i][0]) 73 dl.append(ed) 74 return dl 75 76 def write_Obs_to_dict(o): 77 d = {} 78 d['type'] = 'Obs' 79 d['layout'] = '1' 80 if o.tag: 81 d['tag'] = [o.tag] 82 if o.reweighted: 83 d['reweighted'] = o.reweighted 84 d['value'] = [o.value] 85 data = _gen_data_d_from_list([o]) 86 if len(data) > 0: 87 d['data'] = data 88 cdata = _gen_cdata_d_from_list([o]) 89 if len(cdata) > 0: 90 d['cdata'] = cdata 91 return d 92 93 def write_List_to_dict(ol): 94 _assert_equal_properties(ol) 95 d = {} 96 d['type'] = 'List' 97 d['layout'] = '%d' % len(ol) 98 taglist = [o.tag for o in ol] 99 if np.any([tag is not None for tag in taglist]): 100 d['tag'] = taglist 101 if ol[0].reweighted: 102 d['reweighted'] = ol[0].reweighted 103 d['value'] = [o.value for o in ol] 104 data = _gen_data_d_from_list(ol) 105 if len(data) > 0: 106 d['data'] = data 107 cdata = _gen_cdata_d_from_list(ol) 108 if len(cdata) > 0: 109 d['cdata'] = cdata 110 return d 111 112 def write_Array_to_dict(oa): 113 ol = np.ravel(oa) 114 _assert_equal_properties(ol) 115 d = {} 116 d['type'] = 'Array' 117 d['layout'] = str(oa.shape).lstrip('(').rstrip(')').rstrip(',') 118 taglist = [o.tag for o in ol] 119 if np.any([tag is not None for tag in taglist]): 120 d['tag'] = taglist 121 if ol[0].reweighted: 122 d['reweighted'] = ol[0].reweighted 123 d['value'] = [o.value for o in ol] 124 data = _gen_data_d_from_list(ol) 125 if len(data) > 0: 126 d['data'] = data 127 cdata = _gen_cdata_d_from_list(ol) 128 if len(cdata) > 0: 129 d['cdata'] = cdata 130 return d 131 132 def _nan_Obs_like(obs): 133 samples = [] 134 names = [] 135 idl = [] 136 for key, value in obs.idl.items(): 137 samples.append([np.nan] * len(value)) 138 names.append(key) 139 idl.append(value) 140 my_obs = Obs(samples, names, idl) 141 my_obs._covobs = obs._covobs 142 for name in obs._covobs: 143 my_obs.names.append(name) 144 my_obs.reweighted = obs.reweighted 145 return my_obs 146 147 def write_Corr_to_dict(my_corr): 148 first_not_none = next(i for i, j in enumerate(my_corr.content) if np.all(j)) 149 dummy_array = np.empty((my_corr.N, my_corr.N), dtype=object) 150 dummy_array[:] = _nan_Obs_like(my_corr.content[first_not_none].ravel()[0]) 151 content = [o if o is not None else dummy_array for o in my_corr.content] 152 dat = write_Array_to_dict(np.array(content, dtype=object)) 153 dat['type'] = 'Corr' 154 corr_meta_data = str(my_corr.tag) 155 if 'tag' in dat.keys(): 156 dat['tag'].append(corr_meta_data) 157 else: 158 dat['tag'] = [corr_meta_data] 159 taglist = dat['tag'] 160 dat['tag'] = {} # tag is now a dictionary, that contains the previous taglist in the key "tag" 161 dat['tag']['tag'] = taglist 162 if my_corr.prange is not None: 163 dat['tag']['prange'] = my_corr.prange 164 return dat 165 166 if not isinstance(ol, list): 167 ol = [ol] 168 169 d = {} 170 d['program'] = 'pyerrors %s' % (pyerrorsversion.__version__) 171 d['version'] = '1.1' 172 d['who'] = getpass.getuser() 173 d['date'] = datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S %z') 174 d['host'] = socket.gethostname() + ', ' + platform.platform() 175 176 if description: 177 d['description'] = description 178 179 d['obsdata'] = [] 180 for io in ol: 181 if isinstance(io, Obs): 182 d['obsdata'].append(write_Obs_to_dict(io)) 183 elif isinstance(io, list): 184 d['obsdata'].append(write_List_to_dict(io)) 185 elif isinstance(io, np.ndarray): 186 d['obsdata'].append(write_Array_to_dict(io)) 187 elif isinstance(io, Corr): 188 d['obsdata'].append(write_Corr_to_dict(io)) 189 else: 190 raise Exception("Unkown datatype.") 191 192 def _jsonifier(obj): 193 if isinstance(obj, dict): 194 result = {} 195 for key in obj: 196 if key is True: 197 result['true'] = obj[key] 198 elif key is False: 199 result['false'] = obj[key] 200 elif key is None: 201 result['null'] = obj[key] 202 elif isinstance(key, (int, float, np.floating, np.integer)): 203 result[str(key)] = obj[key] 204 else: 205 raise TypeError('keys must be str, int, float, bool or None') 206 return result 207 elif isinstance(obj, np.integer): 208 return int(obj) 209 elif isinstance(obj, np.floating): 210 return float(obj) 211 else: 212 raise ValueError('%r is not JSON serializable' % (obj,)) 213 214 if indent: 215 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_SINGLE_LINE_ARRAY) 216 else: 217 return json.dumps(d, indent=indent, ensure_ascii=False, default=_jsonifier, write_mode=json.WM_COMPACT)
Generate the string for the export of a list of Obs or structures containing Obs to a pyerrors.input.json(.gz) file
Parameters
- ol (list): List of objects that will be exported. At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. All Obs inside a structure have to be defined on the same set of configurations.
- description (str): Optional string that describes the contents of the json file.
- indent (int): Specify the indentation level of the json file. None or 0 is permissible and saves disk space.
Returns
- json_string (str): String for export to pyerrors.input.json(.gz) file
220def dump_to_json(ol, fname, description='', indent=1, gz=True): 221 """Export a list of Obs or structures containing Obs to a .json(.gz) file. 222 Dict keys that are not JSON-serializable such as floats are converted to strings. 223 224 Parameters 225 ---------- 226 ol : list 227 List of objects that will be exported. At the moment, these objects can be 228 either of: Obs, list, numpy.ndarray, Corr. 229 All Obs inside a structure have to be defined on the same set of configurations. 230 fname : str 231 Filename of the output file. 232 description : str 233 Optional string that describes the contents of the json file. 234 indent : int 235 Specify the indentation level of the json file. None or 0 is permissible and 236 saves disk space. 237 gz : bool 238 If True, the output is a gzipped json. If False, the output is a json file. 239 240 Returns 241 ------- 242 Null 243 """ 244 245 jsonstring = create_json_string(ol, description, indent) 246 247 if not fname.endswith('.json') and not fname.endswith('.gz'): 248 fname += '.json' 249 250 if gz: 251 if not fname.endswith('.gz'): 252 fname += '.gz' 253 254 fp = gzip.open(fname, 'wb') 255 fp.write(jsonstring.encode('utf-8')) 256 else: 257 fp = open(fname, 'w', encoding='utf-8') 258 fp.write(jsonstring) 259 fp.close()
Export a list of Obs or structures containing Obs to a pyerrors.input.json(.gz) file. Dict keys that are not JSON-serializable such as floats are converted to strings.
Parameters
- ol (list): List of objects that will be exported. At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. All Obs inside a structure have to be defined on the same set of configurations.
- fname (str): Filename of the output file.
- description (str): Optional string that describes the contents of the json file.
- indent (int): Specify the indentation level of the json file. None or 0 is permissible and saves disk space.
- gz (bool): If True, the output is a gzipped json. If False, the output is a json file.
Returns
- Null
474def import_json_string(json_string, verbose=True, full_output=False): 475 """Reconstruct a list of Obs or structures containing Obs from a json string. 476 477 The following structures are supported: Obs, list, numpy.ndarray, Corr 478 If the list contains only one element, it is unpacked from the list. 479 480 Parameters 481 ---------- 482 json_string : str 483 json string containing the data. 484 verbose : bool 485 Print additional information that was written to the file. 486 full_output : bool 487 If True, a dict containing auxiliary information and the data is returned. 488 If False, only the data is returned. 489 490 Returns 491 ------- 492 result : list[Obs] 493 reconstructed list of observables from the json string 494 or 495 result : Obs 496 only one observable if the list only has one entry 497 or 498 result : dict 499 if full_output=True 500 """ 501 return _parse_json_dict(json.loads(json_string), verbose, full_output)
Reconstruct a list of Obs or structures containing Obs from a json string.
The following structures are supported: Obs, list, numpy.ndarray, Corr If the list contains only one element, it is unpacked from the list.
Parameters
- json_string (str): json string containing the data.
- verbose (bool): Print additional information that was written to the file.
- full_output (bool): If True, a dict containing auxiliary information and the data is returned. If False, only the data is returned.
Returns
- result (list[Obs]): reconstructed list of observables from the json string
- or
- result (Obs): only one observable if the list only has one entry
- or
- result (dict): if full_output=True
504def load_json(fname, verbose=True, gz=True, full_output=False): 505 """Import a list of Obs or structures containing Obs from a .json(.gz) file. 506 507 The following structures are supported: Obs, list, numpy.ndarray, Corr 508 If the list contains only one element, it is unpacked from the list. 509 510 Parameters 511 ---------- 512 fname : str 513 Filename of the input file. 514 verbose : bool 515 Print additional information that was written to the file. 516 gz : bool 517 If True, assumes that data is gzipped. If False, assumes JSON file. 518 full_output : bool 519 If True, a dict containing auxiliary information and the data is returned. 520 If False, only the data is returned. 521 522 Returns 523 ------- 524 result : list[Obs] 525 reconstructed list of observables from the json string 526 or 527 result : Obs 528 only one observable if the list only has one entry 529 or 530 result : dict 531 if full_output=True 532 """ 533 if not fname.endswith('.json') and not fname.endswith('.gz'): 534 fname += '.json' 535 if gz: 536 if not fname.endswith('.gz'): 537 fname += '.gz' 538 with gzip.open(fname, 'r') as fin: 539 d = json.load(fin) 540 else: 541 if fname.endswith('.gz'): 542 warnings.warn("Trying to read from %s without unzipping!" % fname, UserWarning) 543 with open(fname, 'r', encoding='utf-8') as fin: 544 d = json.loads(fin.read()) 545 546 return _parse_json_dict(d, verbose, full_output)
Import a list of Obs or structures containing Obs from a pyerrors.input.json(.gz) file.
The following structures are supported: Obs, list, numpy.ndarray, Corr If the list contains only one element, it is unpacked from the list.
Parameters
- fname (str): Filename of the input file.
- verbose (bool): Print additional information that was written to the file.
- gz (bool): If True, assumes that data is gzipped. If False, assumes JSON file.
- full_output (bool): If True, a dict containing auxiliary information and the data is returned. If False, only the data is returned.
Returns
- result (list[Obs]): reconstructed list of observables from the json string
- or
- result (Obs): only one observable if the list only has one entry
- or
- result (dict): if full_output=True
629def dump_dict_to_json(od, fname, description='', indent=1, reps='DICTOBS', gz=True): 630 """Export a dict of Obs or structures containing Obs to a .json(.gz) file 631 632 Parameters 633 ---------- 634 od : dict 635 Dict of JSON valid structures and objects that will be exported. 636 At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. 637 All Obs inside a structure have to be defined on the same set of configurations. 638 fname : str 639 Filename of the output file. 640 description : str 641 Optional string that describes the contents of the json file. 642 indent : int 643 Specify the indentation level of the json file. None or 0 is permissible and 644 saves disk space. 645 reps : str 646 Specify the structure of the placeholder in exported dict to be reps[0-9]+. 647 gz : bool 648 If True, the output is a gzipped json. If False, the output is a json file. 649 650 Returns 651 ------- 652 None 653 """ 654 655 if not isinstance(od, dict): 656 raise Exception('od has to be a dictionary. Did you want to use dump_to_json?') 657 658 infostring = ('This JSON file contains a python dictionary that has been parsed to a list of structures. ' 659 'OBSDICT contains the dictionary, where Obs or other structures have been replaced by ' 660 '' + reps + '[0-9]+. The field description contains the additional description of this JSON file. ' 661 'This file may be parsed to a dict with the pyerrors routine load_json_dict.') 662 663 desc_dict = {'INFO': infostring, 'OBSDICT': {}, 'description': description} 664 ol, desc_dict['OBSDICT'] = _ol_from_dict(od, reps=reps) 665 666 dump_to_json(ol, fname, description=desc_dict, indent=indent, gz=gz)
Export a dict of Obs or structures containing Obs to a pyerrors.input.json(.gz) file
Parameters
- od (dict): Dict of JSON valid structures and objects that will be exported. At the moment, these objects can be either of: Obs, list, numpy.ndarray, Corr. All Obs inside a structure have to be defined on the same set of configurations.
- fname (str): Filename of the output file.
- description (str): Optional string that describes the contents of the json file.
- indent (int): Specify the indentation level of the json file. None or 0 is permissible and saves disk space.
- reps (str): Specify the structure of the placeholder in exported dict to be reps[0-9]+.
- gz (bool): If True, the output is a gzipped json. If False, the output is a json file.
Returns
- None
732def load_json_dict(fname, verbose=True, gz=True, full_output=False, reps='DICTOBS'): 733 """Import a dict of Obs or structures containing Obs from a .json(.gz) file. 734 735 The following structures are supported: Obs, list, numpy.ndarray, Corr 736 737 Parameters 738 ---------- 739 fname : str 740 Filename of the input file. 741 verbose : bool 742 Print additional information that was written to the file. 743 gz : bool 744 If True, assumes that data is gzipped. If False, assumes JSON file. 745 full_output : bool 746 If True, a dict containing auxiliary information and the data is returned. 747 If False, only the data is returned. 748 reps : str 749 Specify the structure of the placeholder in imported dict to be reps[0-9]+. 750 751 Returns 752 ------- 753 data : Obs / list / Corr 754 Read data 755 or 756 data : dict 757 Read data and meta-data 758 """ 759 indata = load_json(fname, verbose=verbose, gz=gz, full_output=True) 760 description = indata['description']['description'] 761 indict = indata['description']['OBSDICT'] 762 ol = indata['obsdata'] 763 od = _od_from_list_and_dict(ol, indict, reps=reps) 764 765 if full_output: 766 indata['description'] = description 767 indata['obsdata'] = od 768 return indata 769 else: 770 return od
Import a dict of Obs or structures containing Obs from a pyerrors.input.json(.gz) file.
The following structures are supported: Obs, list, numpy.ndarray, Corr
Parameters
- fname (str): Filename of the input file.
- verbose (bool): Print additional information that was written to the file.
- gz (bool): If True, assumes that data is gzipped. If False, assumes JSON file.
- full_output (bool): If True, a dict containing auxiliary information and the data is returned. If False, only the data is returned.
- reps (str): Specify the structure of the placeholder in imported dict to be reps[0-9]+.
Returns
- data (Obs / list / Corr): Read data
- or
- data (dict): Read data and meta-data