def add_noise(xa_each, outdir, nlon, nlat, nt, map2vec, vec2lat, vec2lon, dtype_f): """ add noise for next loop. Tweaking needed. """ nvec = len(vec2lat) xa_each = np.exp(xa_each) # its log; xa is vector, so there is no undef. data0 = np.memmap(os.path.join(outdir, "param/rivhgt.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="r+") # use carefully! next0 = multiply_normalnoise(xa_each[1, :], 0.25, 0.5, 1.5) tmp = dau.revert_map( next0.astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] tmp[tmp < 0.5] = 0.5 tmp[tmp == 1e+20] = -9999 tmp[tmp > 20] = 20 data0[:, :] = tmp[:, :] del data0 data1 = np.memmap(os.path.join(outdir, "param/rivman.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="r+") # use carefully! next1 = multiply_normalnoise(xa_each[2, :], 0.25, 0.5, 1.5) tmp = dau.revert_map( next1.astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] tmp[tmp < 0.01] = 0.01 tmp[tmp == 1e+20] = -9999 tmp[tmp > 5] = 5 data1[:, :] = tmp[:, :] del data1 data2 = np.memmap(os.path.join(outdir, "param/rivshp.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="r+") # use carefully! next2 = multiply_normalnoise(xa_each[3, :], 0.25, 0.5, 1.5) tmp = dau.revert_map( next2.astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] tmp[tmp < 1] = 1 tmp[tmp == 1e+20] = -9999 tmp[tmp > 20] = 20 data2[:, :] = tmp[:, :] del data2
def save_updates(xa_each, outdir, nlon, nlat, nt, vec2lat, vec2lon, dtype_f): """ save analysis onto file in outdir. Args: xa_each (np.ndarray): analysis array at time nt of eNum (nvars, nReach) nvars are in order of: [outwth, rivman, rivshp] outdir (str): out directory nlon (int): number of longitudinal grid cells nlat (int): number of latitudinal grid cells nt (int): number of time (first dimension) for sim. output files dtype_f (np object): data type for float in numpy object ToDo: Maybe add disturbance on parameters? """ nvec = len(vec2lat) # update outwth data = np.memmap(os.path.join(outdir, "outwth.bin"), dtype=dtype_f, shape=(nt, nlat, nlon), mode="r+") # use carefully! tmp = dau.revert_map(xa_each[0, :].astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] undefloc = (tmp == 1e+20) tmp[undefloc] = 1 tmp = np.exp(tmp) # log tmp[undefloc] = 1e+20 data[-1, :, :] = tmp[:, :] del data # closing and flushing changes to disk data0 = np.memmap(os.path.join(outdir, "param/rivhgt.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="w+") # use carefully! tmp = dau.revert_map(xa_each[1, :].astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] undefloc = (tmp == 1e+20) tmp[undefloc] = 1 # just to avoid overflow tmp = np.exp(tmp) tmp[tmp < 1] = 1 tmp[undefloc] = -9999 data0[:, :] = tmp[:, :] del data0 data1 = np.memmap(os.path.join(outdir, "param/rivman.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="w+") # use carefully! tmp = dau.revert_map(xa_each[2, :].astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] undefloc = (tmp == 1e+20) tmp[undefloc] = 1 tmp = np.exp(tmp) tmp[tmp < 0.01] = 0.01 tmp[undefloc] = -9999 data1[:, :] = tmp[:, :] del data1 data2 = np.memmap(os.path.join(outdir, "param/rivshp.bin"), dtype=dtype_f, shape=(nlat, nlon), mode="w+") # use carefully! tmp = dau.revert_map(xa_each[3, :].astype(dtype_f).reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] undefloc = (tmp == 1e+20) tmp[undefloc] = 1 tmp = np.exp(tmp) tmp[tmp < 1] = 1 tmp[undefloc] = -9999 data2[:, :] = tmp[:, :] del data2
def rewrite_restart(outdir, mapdir, nlon, nlat, nt, map2vec, vec2lat, vec2lon, nlfp=10, dtype_f=np.float32): """ re-write restart file (storage-only) to update initial condition after assimilation based on flow width. This inverting function is case-specific, thus if your assimilation variable changed, you need to review this. Args: outdir (str): out directory mapdir (str): map directory nlon (int): number of longitudinal grid cells nlat (int): number of latitudinal grid cells nt (int): number of time (first dimension) for sim. output files nlfp (int): number of flood plain layers dtype_f (np object): data type for float in numpy object Returns: NoneType Notes: make sure that this function is called after your assimilation results are saved - this func. will read latest values from output files. nt is the number of layers your output have currently - meaning that if your output is currently shaped as [10, 440, 500] then nt=10. This number is usually the number of outer model loop passed. """ nvec = len(vec2lat) # load data in vectorized format rivwth = dau.load_data3d(os.path.join(mapdir, "rivwth_gwdlr.bin"), 1, nlat, nlon, map2vec, nvec, dtype=np.float32)[0] rivlen = dau.load_data3d(os.path.join(mapdir, "rivlen.bin"), 1, nlat, nlon, map2vec, nvec, dtype=np.float32)[0] rivhgt = dau.load_data3d(os.path.join(mapdir, "rivhgt.bin"), 1, nlat, nlon, map2vec, nvec, dtype=np.float32)[0] grarea = dau.load_data3d(os.path.join(mapdir, "ctmare.bin"), 1, nlat, nlon, map2vec, nvec, dtype=np.float32)[0] fldgrd = dau.load_data3d(os.path.join(mapdir, "fldgrd.bin"), nlfp, nlat, nlon, map2vec, nvec, dtype=np.float32)[:] # after assimilation file is saved rivshp = dau.load_data3d(os.path.join(outdir, "param/rivshp.bin"), 1, nlat, nlon, map2vec, nvec, dtype=np.float32)[0] outwth = dau.load_data3d(os.path.join(outdir, "outwth.bin"), nt, nlat, nlon, map2vec, nvec, dtype=np.float32)[-1] storage = calc_storage.get_storage_invertsely(outwth, rivwth, rivlen, rivhgt, rivshp, grarea, fldgrd, nvec, nlfp=nlfp, undef=-9999) restart = np.zeros([2, nlat, nlon]) restart[0] = dau.revert_map(storage[0].reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] restart[1] = dau.revert_map(storage[1].reshape(1, nvec), vec2lat, vec2lon, nlat, nlon)[0] restart.flatten().astype(dtype_f).tofile( os.path.join(outdir, "restart.bin"))