|
| 1 | +#! /usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | + |
| 5 | +import h5py |
| 6 | +import sys |
| 7 | +import numpy as np |
| 8 | + |
| 9 | + |
| 10 | +def toFlatPrimal(ph_bx, ph_by, ph_bz, npx, npy, npz, gn=2): |
| 11 | + |
| 12 | + nbrPoints = npx * npy * npz |
| 13 | + b = np.zeros((nbrPoints, 3), dtype="f") |
| 14 | + |
| 15 | + # pure primal arrays |
| 16 | + bx = np.zeros((npx, npy, npz), dtype=np.float32) |
| 17 | + by = np.zeros((npx, npy, npz), dtype=np.float32) |
| 18 | + bz = np.zeros((npx, npy, npz), dtype=np.float32) |
| 19 | + |
| 20 | + # converts yee to pure primal |
| 21 | + # by averaging in the dual direction |
| 22 | + # first and last will be fucked |
| 23 | + bx[:, :, 0] = ( |
| 24 | + ph_bx[gn:-gn, gn - 1 : -gn + 1][:, 1:] + ph_bx[gn:-gn, gn - 1 : -gn + 1][:, :-1] |
| 25 | + ) * 0.5 |
| 26 | + by[:, :, 0] = ( |
| 27 | + ph_by[gn - 1 : -gn + 1, gn:-gn][1:, :] + ph_by[gn - 1 : -gn + 1, gn:-gn][:-1, :] |
| 28 | + ) * 0.5 |
| 29 | + bz[:, :, 0] = ( |
| 30 | + ph_bz[gn - 1 : -gn + 1, gn - 1 : -gn + 1][1:, 1:] |
| 31 | + + ph_bz[gn - 1 : -gn + 1, gn - 1 : -gn + 1][:-1, :-1] |
| 32 | + ) * 0.5 |
| 33 | + |
| 34 | + bx[:, :, 1] = bx[:, :, 0] |
| 35 | + by[:, :, 1] = by[:, :, 0] |
| 36 | + bz[:, :, 1] = bz[:, :, 0] |
| 37 | + |
| 38 | + b[:, 0] = bx.flatten(order="F") |
| 39 | + b[:, 1] = by.flatten(order="F") |
| 40 | + b[:, 2] = bz.flatten(order="F") |
| 41 | + |
| 42 | + return b |
| 43 | + |
| 44 | + |
| 45 | +def boxFromPatch(patch): |
| 46 | + lower = patch.attrs["lower"] |
| 47 | + upper = patch.attrs["upper"] |
| 48 | + return [lower[0], upper[0], lower[1], upper[1], 0, 0] # 2D |
| 49 | + |
| 50 | + |
| 51 | +def nbrNodes(box): |
| 52 | + lower = box[0], box[2], box[4] |
| 53 | + upper = box[1], box[3], box[5] |
| 54 | + npx = upper[0] - lower[0] + 1 + 1 |
| 55 | + npy = upper[1] - lower[1] + 1 + 1 |
| 56 | + npz = upper[2] - lower[2] + 1 + 1 |
| 57 | + return npx, npy, npz |
| 58 | + |
| 59 | + |
| 60 | +def main(): |
| 61 | + |
| 62 | + path = sys.argv[1] |
| 63 | + phare_h5 = h5py.File(f"{path}/EM_B.h5", "r") |
| 64 | + times_str = list(phare_h5["t"].keys()) |
| 65 | + times = np.asarray([float(time) for time in times_str]) |
| 66 | + times.sort() |
| 67 | + root_spacing = phare_h5.attrs["cell_width"] |
| 68 | + |
| 69 | + max_nbr_level = 0 |
| 70 | + for time in times_str: |
| 71 | + nbrLevels = len(phare_h5["t"][time].keys()) |
| 72 | + if max_nbr_level < nbrLevels: |
| 73 | + max_nbr_level = nbrLevels |
| 74 | + |
| 75 | + vtk = h5py.File(f"{path}/EM_B.vtkhdf", "w") |
| 76 | + root = vtk.create_group("VTKHDF", track_order=True) |
| 77 | + root.attrs["Version"] = (2, 2) |
| 78 | + type = b"OverlappingAMR" |
| 79 | + root.attrs.create("Type", type, dtype=h5py.string_dtype("ascii", len(type))) |
| 80 | + description = b"XYZ" |
| 81 | + root.attrs.create( |
| 82 | + "GridDescription", |
| 83 | + description, |
| 84 | + dtype=h5py.string_dtype("ascii", len(description)), |
| 85 | + ) |
| 86 | + origin = [0, 0, 0] |
| 87 | + root.attrs.create("Origin", origin, dtype="f") |
| 88 | + |
| 89 | + numberOfTimes = 3 # times.size |
| 90 | + |
| 91 | + steps = root.create_group("Steps") |
| 92 | + steps.attrs.create("NSteps", data=numberOfTimes, dtype="i8") |
| 93 | + steps.create_dataset("Values", data=times[:numberOfTimes]) |
| 94 | + |
| 95 | + print(f"maxlevel:{max_nbr_level}") |
| 96 | + |
| 97 | + for ilvl in range(max_nbr_level)[:]: |
| 98 | + |
| 99 | + print(f"Processing level {ilvl}") |
| 100 | + |
| 101 | + lvl = root.create_group(f"Level{ilvl}") |
| 102 | + lvl_spacing = root_spacing |
| 103 | + lvl_spacing = [dl / 2**ilvl for dl in lvl_spacing] + [0.0] |
| 104 | + lvl.attrs.create("Spacing", lvl_spacing, dtype="f") |
| 105 | + steps_lvl = steps.create_group(f"Level{ilvl}") |
| 106 | + |
| 107 | + AMRBox = [] |
| 108 | + step_nbrBoxes = [] |
| 109 | + AMRBoxOffsets = [] |
| 110 | + dataOffsets = [] |
| 111 | + |
| 112 | + cellData_g = lvl.create_group("CellData") |
| 113 | + pointData_g = lvl.create_group("PointData") |
| 114 | + fieldData_g = lvl.create_group("FieldData") |
| 115 | + cellDataOffset_g = steps_lvl.create_group("CellDataOffset") |
| 116 | + pointDataOffset_g = steps_lvl.create_group("PointDataOffset") |
| 117 | + FieldDataOffset_g = steps_lvl.create_group("FieldDataOffset") |
| 118 | + |
| 119 | + first = True |
| 120 | + |
| 121 | + # these are values for the first time |
| 122 | + # they will be reset for other times |
| 123 | + current_size = 0 |
| 124 | + amr_box_offset = 0 |
| 125 | + |
| 126 | + for time in times[:numberOfTimes]: |
| 127 | + nbr_boxes = 0 |
| 128 | + print(f"time {time}") |
| 129 | + time_str = f"{time:.10f}" |
| 130 | + phare_lvl_name = f"pl{ilvl}" |
| 131 | + dataOffsets += [current_size] |
| 132 | + print("amr_box_offset", amr_box_offset) |
| 133 | + AMRBoxOffsets += [amr_box_offset] |
| 134 | + # pass this time if this level does not exist |
| 135 | + if phare_lvl_name not in phare_h5["t"][time_str].keys(): |
| 136 | + print(f"no level {ilvl} at time {time}") |
| 137 | + continue |
| 138 | + phare_lvl = phare_h5["t"][time_str][phare_lvl_name] |
| 139 | + |
| 140 | + for patch_id in list(phare_lvl.keys())[:]: |
| 141 | + # print(f"patch {patch_id}") |
| 142 | + patch = phare_lvl[patch_id] |
| 143 | + |
| 144 | + ph_bx = patch["EM_B_x"][:] |
| 145 | + ph_by = patch["EM_B_y"][:] |
| 146 | + ph_bz = patch["EM_B_z"][:] |
| 147 | + |
| 148 | + box = boxFromPatch(patch) |
| 149 | + AMRBox.append(box) |
| 150 | + nbr_boxes += 1 |
| 151 | + npx, npy, npz = nbrNodes(box) |
| 152 | + b = toFlatPrimal(ph_bx, ph_by, ph_bz, npx, npy, npz) |
| 153 | + # b = np.ones(12 * 14 * 2) # np.ones((12 * 14, 3), dtype="f") |
| 154 | + # print(f"b shape :{b.shape} npx:{npx} npy:{npy}") |
| 155 | + # print(f"box:{box}") |
| 156 | + |
| 157 | + if first: |
| 158 | + # this is the first patch of the first time |
| 159 | + # for this level, we need to create the dataset |
| 160 | + # the first dimension is the total # of points |
| 161 | + # which is unknown hence the None for maxshape |
| 162 | + # print(f"b shape :{b.shape[0]}") |
| 163 | + pointData_b = pointData_g.create_dataset( |
| 164 | + "B", data=b, maxshape=(None, 3) |
| 165 | + ) |
| 166 | + first = False |
| 167 | + |
| 168 | + else: |
| 169 | + # print("else") |
| 170 | + # print(f"b shape :{b.shape[0]}") |
| 171 | + # dataset already created with shape (current_size,3) |
| 172 | + # we add b.shape[0] points (=npx*npy) to the first dim |
| 173 | + # hence need to resize the dataset. |
| 174 | + pointData_b.resize(current_size + b.shape[0], axis=0) |
| 175 | + pointData_b[current_size:, :] = b |
| 176 | + # pass |
| 177 | + |
| 178 | + current_size += b.shape[0] |
| 179 | + # print(f"current_size:{current_size}") |
| 180 | + |
| 181 | + # of of the patch loops at that time |
| 182 | + |
| 183 | + # number of boxes added for ilvl across all times |
| 184 | + amr_box_offset += nbr_boxes |
| 185 | + step_nbrBoxes += [nbr_boxes] |
| 186 | + |
| 187 | + lvl.create_dataset("AMRBox", data=AMRBox) |
| 188 | + steps_lvl.create_dataset("AMRBoxOffset", data=AMRBoxOffsets) |
| 189 | + steps_lvl.create_dataset("NumberOfAMRBox", data=step_nbrBoxes) |
| 190 | + pointDataOffset_g.create_dataset("B", data=dataOffsets) |
| 191 | + |
| 192 | + vtk.close() |
| 193 | + |
| 194 | + |
| 195 | +if __name__ == "__main__": |
| 196 | + main() |
0 commit comments