def create_Efield(cfg, xg, params): cfg["E0dir"].mkdir(parents=True, exist_ok=True) # %% CREATE ELECTRIC FIELD DATASET llon = 100 llat = 100 # NOTE: cartesian-specific code if xg["lx"][1] == 1: llon = 1 elif xg["lx"][2] == 1: llat = 1 thetamin = xg["theta"].min() thetamax = xg["theta"].max() mlatmin = 90 - np.degrees(thetamax) mlatmax = 90 - np.degrees(thetamin) mlonmin = np.degrees(xg["phi"].min()) mlonmax = np.degrees(xg["phi"].max()) # add a 1% buff latbuf = 0.01 * (mlatmax - mlatmin) lonbuf = 0.01 * (mlonmax - mlonmin) E = xarray.Dataset( coords={ "time": datetime_range(cfg["time"][0], cfg["time"][0] + cfg["tdur"], cfg["dtE0"]), "mlat": np.linspace(mlatmin - latbuf, mlatmax + latbuf, llat), "mlon": np.linspace(mlonmin - lonbuf, mlonmax + lonbuf, llon), }) Nt = E.time.size # %% INTERPOLATE X2 COORDINATE ONTO PROPOSED MLON GRID xgmlon = np.degrees(xg["phi"][0, :, 0]) # xgmlat = 90 - np.degrees(xg["theta"][0, 0, :]) f = interp1d(xgmlon, xg["x2"][2:xg["lx"][1] + 2], kind="linear", fill_value="extrapolate") x2i = f(E["mlon"]) # f = interp1d(xgmlat, xg["x3"][2:lx3 + 2], kind='linear', fill_value="extrapolate") # x3i = f(E["mlat"]) # %% CREATE DATA FOR BACKGROUND ELECTRIC FIELDS if "Exit" in cfg: E["Exit"] = (("time", "mlon", "mlat"), cfg["Exit"] * np.ones( (Nt, llon, llat))) else: E["Exit"] = (("time", "mlon", "mlat"), np.zeros((Nt, llon, llat))) if "Eyit" in cfg: E["Eyit"] = (("time", "mlon", "mlat"), cfg["Eyit"] * np.ones( (Nt, llon, llat))) else: E["Eyit"] = (("time", "mlon", "mlat"), np.zeros((Nt, llon, llat))) # %% CREATE DATA FOR BOUNDARY CONDITIONS FOR POTENTIAL SOLUTION # if 0 data is interpreted as FAC, else we interpret it as potential E["flagdirich"] = (("time", ), np.zeros(Nt, dtype=np.int32)) E["Vminx1it"] = (("time", "mlon", "mlat"), np.zeros((Nt, llon, llat))) E["Vmaxx1it"] = (("time", "mlon", "mlat"), np.zeros((Nt, llon, llat))) # these are just slices E["Vminx2ist"] = (("time", "mlat"), np.zeros((Nt, llat))) E["Vmaxx2ist"] = (("time", "mlat"), np.zeros((Nt, llat))) E["Vminx3ist"] = (("time", "mlon"), np.zeros((Nt, llon))) E["Vmaxx3ist"] = (("time", "mlon"), np.zeros((Nt, llon))) for i in range(Nt): # ZEROS TOP CURRENT AND X3 BOUNDARIES DON'T MATTER SINCE PERIODIC # COMPUTE KHI DRIFT FROM APPLIED POTENTIAL vel3 = np.empty((llon, llat)) for j in range(llat): vel3[:, j] = params["v0"] * np.tanh( x2i / params["ell"]) - params["vn"] vel3 = np.flipud(vel3) # CONVERT TO ELECTRIC FIELD (actually -1* electric field...) E2slab = vel3 * params["B1val"] # INTEGRATE TO PRODUCE A POTENTIAL OVER GRID - then save the edge boundary conditions DX2 = np.diff(x2i) DX2 = np.append(DX2, DX2[-1]) Phislab = np.cumsum(E2slab * DX2, axis=0) # use a forward difference E["Vmaxx2ist"][i, :] = Phislab[-1, :] E["Vminx2ist"][i, :] = Phislab[0, :] # %% Write electric field data to file gemini3d.write.Efield(E, cfg["E0dir"], cfg["file_format"])
def fast2GEMINI(cfg, xg): # output dict. pg = {} # read in the data [invlat, eflux, chare] = readfast(filename) # smooth data a bit prior to insertion into model lsmooth = 0 [efluxsmooth, charesmooth] = smoothfast(lsmooth, eflux, chare) # basic grid info gridmlat = 90 - xg["theta"] * 180 / pi gridmlon = xg["phi"] * 180 / pi mlatmin = np.min(gridmlat) mlatmax = np.max(gridmlat) mlonmin = np.min(gridmlon) mlonmax = np.max(gridmlon) # precipitation input grids llon = 128 llat = invlat.size mlon = np.linspace(mlonmin, mlonmax, llon) mlat = invlat mlonctr = np.average(mlon) mlatctr = np.average(mlat) # fast data may need to be sorted along the latitude axis isort = np.argsort(mlat) mlat = mlat[isort] efluxsmooth = efluxsmooth[isort] charesmooth = charesmooth[isort] # for convenience recenter grid on what the user has made #dmlat=np.average(gridmlat)-mlatctr dmlat = 0 mlat = mlat + dmlat # time grid for precipitation time = datetime_range(cfg["time"][0], cfg["time"][0] + cfg["tdur"], cfg["dtprec"]) lt = len(time) t = np.empty((lt)) for k in range(0, lt): t[k] = time[k].timestamp() meant = np.average(t) # longitude shape Q = np.empty((lt, llon, llat)) E0 = np.empty((lt, llon, llat)) siglon = 15 sigt = 100 for k in range(0, lt): tshape = np.exp(-(t[k] - meant)**2 / 2 / sigt**2) for ilon in range(0, llon): lonshape = np.exp(-(mlon[ilon] - mlonctr)**2 / 2 / siglon**2) Q[k, ilon, :] = tshape * lonshape * efluxsmooth[:] E0[k, ilon, :] = charesmooth[:] # fill values Q[Q < 0] = 0 E0[E0 < 101] = 101 # create xarray dataset pg = xarray.Dataset( { "Q": (("time", "mlon", "mlat"), Q), "E0": (("time", "mlon", "mlat"), E0), }, coords={ "time": time, "mlat": mlat, "mlon": mlon, }, ) # make a representative plot if required if debug: plt.subplots(1, 2, dpi=100) plt.subplot(1, 2, 1) plt.pcolormesh(mlon, mlat, Q[lt // 2, :, :].transpose()) plt.colorbar() plt.title("energy flux") plt.xlabel("mlon") plt.ylabel("mlat") plt.subplot(1, 2, 2) plt.pcolormesh(mlon, mlat, E0[lt // 2, :, :].transpose()) plt.colorbar() plt.title("char. en.") plt.xlabel("mlon") plt.ylabel("mlat") plt.show(block=False) # write these to the simulation input directory write.precip(pg, cfg["precdir"], cfg["file_format"]) return
def create_precip(cfg, xg, params): """write particle precipitation to disk""" # %% CREATE PRECIPITATION INPUT DATA # Q: energy flux [mW m^-2] # E0: characteristic energy [eV] pg = precip_grid(cfg, xg) # did user specify on/off time? if not, assume always on. t0 = pg.time[0].data if "precip_startsec" in cfg: t = t0 + np.timedelta64(cfg["precip_startsec"]) i_on = abs(pg.time - t).argmin().item() else: i_on = 0 if "precip_endsec" in cfg: t = t0 + np.timedelta64(cfg["precip_endsec"]) i_off = abs(pg.time - t).argmin().item() else: i_off = pg.time.size assert np.isfinite(cfg["E0precip"]), "E0 precipitation must be finite" assert cfg["E0precip"] > 0, "E0 precip must be positive" assert cfg["E0precip"] < 100e6, "E0 precip must not be relativistic 100 MeV" llon = 512 llat = 512 # NOTE: cartesian-specific code if xg["lx"][1] == 1: llon = 1 elif xg["lx"][2] == 1: llat = 1 thetamin = xg["theta"].min() thetamax = xg["theta"].max() mlatmin = 90 - np.degrees(thetamax) mlatmax = 90 - np.degrees(thetamin) mlonmin = np.degrees(xg["phi"].min()) mlonmax = np.degrees(xg["phi"].max()) # add a 1% buff latbuf = 0.01 * (mlatmax - mlatmin) lonbuf = 0.01 * (mlonmax - mlonmin) time = datetime_range(cfg["time"][0], cfg["time"][0] + cfg["tdur"], cfg["dtprec"]) pg = xarray.Dataset( { "Q": (("time", "mlon", "mlat"), np.zeros((len(time), llon, llat))), "E0": (("time", "mlon", "mlat"), np.zeros( (len(time), llon, llat))), }, coords={ "time": time, "mlat": np.linspace(mlatmin - latbuf, mlatmax + latbuf, llat), "mlon": np.linspace(mlonmin - lonbuf, mlonmax + lonbuf, llon), }, ) Nt = pg.time.size # %% INTERPOLATE X2 COORDINATE ONTO PROPOSED MLON GRID xgmlon = np.degrees(xg["phi"][0, :, 0]) # xgmlat = 90 - np.degrees(xg["theta"][0, 0, :]) f = interp1d(xgmlon, xg["x2"][2:xg["lx"][1] + 2], kind="linear", fill_value="extrapolate") x2i = f(pg["mlon"]) # f = interp1d(xgmlat, xg["x3"][2:lx3 + 2], kind='linear', fill_value="extrapolate") # x3i = f(E["mlat"]) # NOTE: in future, E0 could be made time-dependent in config.nml as 1D array for i in range(i_on, i_off): pg["Q"][i, :, :] = precip_SAID(pg, params, x2i, cfg["Qprecip"], cfg["Qprecip_background"]) pg["E0"][i, :, :] = cfg["E0precip"] assert np.isfinite(pg["Q"]).all(), "Q flux must be finite" assert (pg["Q"] >= 0).all(), "Q flux must be non-negative" gemini3d.write.precip(pg, cfg["precdir"], cfg["file_format"])