Source code for pysac.io.gdf_writer

"""
Routines for the writing of GDF files
"""

import copy

import numpy as np
import astropy.units as u

import h5py
from h5py import h5s, h5p, h5fd

__all__ = ['write_field', 'write_field_u', 'create_file', 'SimulationParameters']


[docs]class SimulationParameters(dict): def __init__(self, *args, **kwargs): self.REQUIRED_KEYS = ('refine_by', 'dimensionality', 'domain_dimensions', 'current_time', 'domain_left_edge', 'domain_right_edge', 'unique_identifier', 'cosmological_simulation', 'num_ghost_zones', 'field_ordering', 'boundary_conditions') for key in self.REQUIRED_KEYS: self[key] = None self['refine_by'] = 0 self['cosmological_simulation'] = 0 self['unique_identifier'] = 'sacgdf2014' super(SimulationParameters, self).__init__(*args, **kwargs) def __str__(self): head = """ Simulation Parameters Object ---------------------------- Required Attributes: """ for key in self.REQUIRED_KEYS: head += key+': {{{0}}}\n'.format(key) others = copy.copy(self) for key in self.REQUIRED_KEYS: others.pop(key) if len(others): tail = """ Other Attributes: """ for key in others: tail += key+': {{{0}}}\n'.format(key) else: tail = '' string = head.format(**self) + tail.format(**others) return string def __repr__(self): return str(self)
[docs]def create_file(f, simulation_parameters, grid_dimensions, data_author=None, data_comment=None): """ Do all the structral creation of a gdf file. gdf files should be written in a x,y,z order, please swap them before calling this function!! Parameters ---------- gdf_path: string or h5py instance Filename to save out simulation_parameters: dict Key value pairs for attributes to be written to the simulation_parameters group. grid_dimensions data_author: (optional) string Author to write to file data_comment: (optional) string A comment to write to file Returns ------- h5py.File instance Notes ----- GDF is defined here: https://bitbucket.org/yt_analysis/grid_data_format/ """ if isinstance(f, basestring): f = h5py.File(f, 'a') # "gridded_data_format" group g = f.create_group("gridded_data_format") g.attrs["data_software"] = "Sheffield Advanced Code" g.attrs["data_software_version"] = "pySAC0.2" if data_author is not None: g.attrs["data_author"] = data_author if data_comment is not None: g.attrs["data_comment"] = data_comment # "simulation_parameters" group g = f.create_group("simulation_parameters") for key, value in simulation_parameters.items(): g.attrs[key] = value # "field_types" group g = f.create_group("field_types") # "particle_types" group g = f.create_group("particle_types") # root datasets -- info about the grids f["grid_dimensions"] = np.reshape(grid_dimensions, (1, 3)) #needs to be 1XN f["grid_left_index"] = np.zeros((1,3)) #needs to be 1XN f["grid_level"] = np.zeros(1) # @todo: Fill with proper values f["grid_parent_id"] = np.zeros(1) f["grid_particle_count"] = np.zeros((1,1)) # "data" group -- where we should spend the most time d = f.create_group("data") gr = d.create_group("grid_%010i"%0) return f
[docs]def write_field_u(gdf_file, data, field_title, field_name, field_shape=None, arr_slice=np.s_[:], staggering=0, collective=False, api='high'): """ Write a field to an existing gdf file. Parameters ---------- gdf_file: h5py.File Open, writeable gdf file data: astropy.units.Quantity The data to be written field_tile: str The name of the field dataset field_name: str The long name for the field field_shape: (optional) tuple The shape of the whole dataset, if not specified use data.shape. arr_slice: (optional) np.s_ The slice of the whole dataset to write staggering: (optional) int The 'staggering' of the gdf field """ gr = gdf_file["/data/grid_%010i"%0] field = data.si if not field_shape: field_shape = field.shape dset = gr.create_dataset(field_title, field_shape, dtype='d') fv = gdf_file['field_types'].create_group(field_title) fv.attrs['field_name'] = field_name fv.attrs['field_to_cgs'] = field.unit.to_system(u.cgs)[0].scale fv.attrs['field_units'] = np.string_(field.unit.to_string("latex").strip('$')) fv.attrs['staggering'] = staggering # gr[field_title][arr_slice] = np.array(field) if api == 'high': _write_dset_high(dset, field, arr_slice, collective=collective) elif api == 'low': _write_dset_low(dset, field, arr_slice, collective=collective) else: raise ValueError("Please specifiy 'high' or 'low'")
[docs]def write_field(gdf_file, field, field_shape=None, arr_slice=np.s_[:], collective=False, api='high'): """ Write a field to an existing gdf file. Parameters ---------- gdf_file: h5py.File Open, writeable gdf file field: dict A dict containing the following keys: 'field': ndarray 'field_title': string 'field_name': string 'field_units': string 'field_to_cgs': float 'staggering': 0 or 1 arr_slice: (optional) np.s_ The slice of the whole dataset to write staggering: (optional) int The 'staggering' of the gdf field collective: bool Use MPI collective write api: str 'high' or 'low' signifiyng the h5py API to use for write. Used for benchmarking. """ gr = gdf_file["/data/grid_%010i"%0] if not field_shape: field_shape = field['field'].shape dset = gr.create_dataset(field['field_title'], field_shape, dtype='d') fv = gdf_file['field_types'].create_group(field['field_title']) fv.attrs['field_name'] = field['field_name'] fv.attrs['field_to_cgs'] = field['field_to_cgs'] fv.attrs['field_units'] = field['field_units'] fv.attrs['staggering'] = field['staggering'] if api == 'high': _write_dset_high(dset, field['field'], arr_slice, collective=collective) elif api == 'low': _write_dset_low(dset, field['field'], arr_slice, collective=collective) else: raise ValueError("Please specifiy 'high' or 'low'")
def _write_dset_high(dset, data, arr_slice,collective=False): if collective: with dset.collective: dset[arr_slice] = np.ascontiguousarray(data) else: dset[arr_slice] = np.ascontiguousarray(data) def _write_dset_low(dset, data, arr_slice, collective=False): memory_space = h5s.create_simple(data.shape) file_space = dset.id.get_space() s = (arr_slice[0].start,arr_slice[1].start,arr_slice[2].start) e = (arr_slice[0].stop,arr_slice[1].stop,arr_slice[2].stop) count = tuple([ee - ss for ss,ee in zip(s,e)]) file_space.select_hyperslab(s, count) if collective: dxpl = h5p.create(h5p.DATASET_XFER) dxpl.set_dxpl_mpio(h5fd.MPIO_COLLECTIVE) else: dxpl = None dset.id.write(memory_space, file_space, np.ascontiguousarray(data),dxpl=dxpl)