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