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