diff --git a/python/amun.py b/python/amun.py new file mode 100644 index 0000000..0e139cb --- /dev/null +++ b/python/amun.py @@ -0,0 +1,204 @@ +""" +================================================================================ + + This file is part of the AMUN source code, a program to perform + Newtonian or relativistic magnetohydrodynamical simulations on uniform or + adaptive mesh. + + Copyright (C) 2018 Grzegorz Kowal <grzegorz@amuncode.org> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +================================================================================ + + module: AMUN + + Python module with subroutines to read AMUN code HDF5 files. + + The only requirements for this module are: + - h5py + - numpy + +-------------------------------------------------------------------------------- +""" +import h5py as h5 +import numpy as np +import os.path as op + +def amun_attribute(fname, aname): + ''' + Subroutine to reads global attributes from AMUN HDF5 snapshots. + + Arguments: + + fname - the AMUN HDF5 file name; + aname - the attribute name; + + Return values: + + ret - the value read from the attribute; + + Examples: + + time = amun_attribute('p000010_00000.h5', 'time') + + ''' + # open the file + # + f = h5.File(fname, 'r') + + # check if the file is written in the AMUN format + # + if f.attrs.get('code')[0].astype(str) != "AMUN" or \ + not 'attributes' in f or \ + not 'coordinates' in f or \ + not 'variables' in f: + print('It seems this HDF5 file is corrupted or not compatible with the AMUN format!') + f.close() + return False + + # open the group of attributes + # + g = f['attributes'].attrs + + # get attribute's value + # + ret = g.get(aname) + if len(ret) == 1: + ret = ret[0] + + # close the file + # + f.close() + + # return the value of attribute + # + return ret + +def amun_dataset(fname, vname): + ''' + Subroutine to reads dataset from AMUN HDF5 snapshots. + + Arguments: + + fname - the AMUN HDF5 file name; + vname - the variable name; + + Return values: + + ret - the array of values for the variable; + + Examples: + + dn = amun_dataset('p000010_00000.h5', 'dens') + + ''' + # open the file + # + + f = h5.File(fname, 'r') + + # check if the file is written in the AMUN format + # + if f.attrs.get('code')[0].astype(str) != "AMUN" or \ + not 'attributes' in f or \ + not 'coordinates' in f or \ + not 'variables' in f: + print('It seems this HDF5 file is corrupted or not compatible with the AMUN format!') + return False + + # build the list of supported variables + # + variables = [] + for var in f['variables'].keys(): + variables.append(var) + + # check if the requested variable is in the variable list + # + if not vname in variables: + print('The requested variable cannot be extracted from the file datasets!') + return False + + # get attributes necessary to reconstruct the domain + # + g = f['attributes'].attrs + + # get the snapshot number, the number of domain files, and the number of blocks + # + nr = g.get('isnap')[0] + nc = g.get('nprocs')[0] + nl = g.get('nleafs')[0] + + # prepare array to hold data + # + bm = g.get('dims') + if bm[2] > 1: + ndims = 3 + else: + ndims = 2 + rm = g.get('rdims') + ng = g.get('nghosts') + ml = g.get('maxlev')[0] + dm = rm[0:ndims] * bm[0:ndims] * 2**(ml - 1) + ret = np.zeros(dm[::-1]) + + f.close() + + # iterate over all subdomain files + # + dname = op.dirname(fname) + for n in range(nc): + lname = op.join(dname, 'p%06d_%05d.h5' % (nr, n)) + f = h5.File(lname, 'r') + g = f['attributes'].attrs + dblocks = g.get('dblocks')[0] + if dblocks > 0: + g = f['coordinates'] + levels = g['levels'][()] + coords = g['coords'][()] + g = f['variables'] + if ndims == 3: + dataset = g[vname][ng:-ng,ng:-ng,ng:-ng,:] + for l in range(dblocks): + nn = 2**(ml - levels[l]) + cm = bm * nn + ibeg = coords[:,l] * cm[:] + iend = ibeg + cm[:] + ib, jb, kb = ibeg[0], ibeg[1], ibeg[2] + ie, je, ke = iend[0], iend[1], iend[2] + ret[kb:ke,jb:je,ib:ie] = np.repeat(np.repeat(np.repeat(dataset[:,:,:,l], nn, axis = 0), nn, axis = 1), nn, axis = 2) + else: + dataset = g[vname][0,ng:-ng,ng:-ng,:] + for l in range(dblocks): + nn = 2**(ml - levels[l]) + cm = bm[0:ndims] * nn + ibeg = coords[:,l] * cm[:] + iend = ibeg + cm[:] + ib, jb = ibeg[0], ibeg[1] + ie, je = iend[0], iend[1] + ret[jb:je,ib:ie] = np.repeat(np.repeat(dataset[:,:,l], nn, axis = 0), nn, axis = 1) + f.close() + + return ret + +if __name__ == "__main__": + fname = './p000030_00000.h5' + + ret = amun_attribute(fname, 'time') + print(ret) + ret = amun_attribute(fname, 'dims') + print(ret) + + ret = amun_dataset(fname, 'dens') + print(ret.shape, ret.min(), ret.max())