import os from multiprocessing import Pool from functools import partial import time from shutil import rmtree import numpy as np from scipy.interpolate import interp1d from copy import deepcopy import ramRW_new as ramRW from DataBase import DataBase class BathyM: def __init__(self, ran=None, depth=None): self.r = ran self.d = depth class SSP_: def __init__(self, r, z, c): self.r = r self.z = z self.c = c class Sed: def __init__(self, z, cp, cs, rho, a_p, a_s): self.z = z self.cp = cp self.cs = cs self.rho = rho self.a_p = a_p self.a_s = a_s class Coord: def __init__(self, lon, lat): self.lon = lon self.lat = lat class RANDI_Para: def __init__(self, baseDir, freq, lon, lat, Range, dRange, dTheta, v_ship, l_ship, theta=0): self.baseDir = baseDir self.freq = freq self.lon = lon self.lat = lat self.Range = Range self.dRange = dRange self.dTheta = dTheta self.v_ship = v_ship self.l_ship = l_ship self.theta = theta def refreshTheta(self, theta): self.theta = theta return self def RANDI_GetSeaDepth(data, N, coordS, R, azi): r = np.linspace(0, R, N) lon = coordS.lon + r * np.sin(azi) / (111 * np.cos(coordS.lat / 180 * np.pi)) lat = coordS.lat + r * np.cos(azi) / 111 z = np.zeros(N) for it in range(N): data.set_coord(lat[it], lon[it]) z[it] = data.get_bottomDepth() return r, z def RANDI_GetMeanProfile(data, N, coordS, R, azi): r = np.linspace(0, R, N) lon = coordS.lon + r * np.sin(azi) / (111 * np.cos(coordS.lat / 180 * np.pi)) lat = coordS.lat + r * np.cos(azi) / 111 sal = np.full([len(data.depthGrid), N], np.nan) tem = np.full([len(data.depthGrid), N], np.nan) for i in range(N): data.set_coord(lat[i], lon[i]) salPf = data.get_salRawProfile() temPf = data.get_temRawProfile() if len(salPf.x) > 1: sal[0:len(salPf.x), i] = salPf.y tem[0:len(temPf.x), i] = temPf.y sal = np.ma.masked_array(sal, np.isnan(sal)) tem = np.ma.masked_array(tem, np.isnan(tem)) sal_m = np.mean(sal, 1) tem_m = np.mean(tem, 1) z = data.depthGrid[~sal_m.mask] sal_m = sal_m[~sal_m.mask] tem_m = tem_m[~tem_m.mask] return z, sal_m, tem_m def RANDI_GetEnv(data, coordS, coordR=None, R=None, azi=None): if coordR == None: azi = azi / 180 * np.pi lon = coordS.lon + R * np.sin(azi) / (111 * np.cos(coordS.lat / 180 * np.pi)) lat = coordS.lat + R * np.cos(azi) / 111 coordR = Coord(lon, lat) if R == None: x = (coordR.lon - coordS.lon) * (111 * np.cos(coordS.lat / 180 * np.pi)) y = (coordR.lat - coordS.lat) * 111 R = np.sqrt(x * x + y * y) if y > 0: azi = np.arctan(x / y) elif y == 0: azi = np.sign(x) * np.pi / 2 else: azi = np.arctan(x / y) + np.pi # Get Bathymetry N = int(np.ceil(R / 10) + 1) r, z = RANDI_GetSeaDepth(data, N, coordS, R, azi) bathym = BathyM(r, z) # plt.plot(r, z) # plt.gca().invert_yaxis() # plt.show() # Get Sound Speed Profile z_ssp, sal_m, tem_m = RANDI_GetMeanProfile(data, N, coordS, R, azi) if max(bathym.d) > z_ssp[-1]: z_ssp = np.append(z_ssp, max(bathym.d)) sal_m = np.append(sal_m, sal_m[-1]) tem_m = np.append(tem_m, tem_m[-1]) c_ssp = DataBase.soundSpeed(tem_m, sal_m, z_ssp) ssp = SSP_(0, z_ssp, c_ssp) # plt.plot(c_ssp, z_ssp) # plt.gca().invert_yaxis() # plt.show() # Sediment z = np.array([0, 50]) cp = np.array([1550, 1590]) cs = np.array([0, 0]) rho = np.array([1.3, 1.5]) a_p = np.array([0.1, 0.1]) a_s = np.array([0, 0]) sed = Sed(z, cp, cs, rho, a_p, a_s) return bathym, ssp, sed def RANDI_writeRAMin(baseDir, data, freq, dTheta, lat, lon, Range, rd, ship_sd, SeaDepthLim): t1 = time() btyFile = open("bty", 'w') for theta in np.arange(0, 360, dTheta): [bathm, ssp, sed] = RANDI_GetEnv(data, Coord(lon, lat), R=Range, azi=theta) for dd in bathm.d: btyFile.write(str(dd) + ' ') btyFile.write('\n') idx = np.where(bathm.d < SeaDepthLim) if len(idx[0]) > 0: bathm.r = bathm.r[0:idx[0][0]] bathm.d = bathm.d[0:idx[0][0]] title = "Waveguide" # Source and receiving position bathm.r = bathm.r * 1000 # km -> m rmax = max(bathm.r) # Maximum receiving range (unit: m) zmax = round(max(bathm.d) + 5 * 1500 / freq) # Maximum receiving depth (uint: m) zmplt = 0 # round(max(bathm.d)*1.05) # Maximum depth of plot (uint: m) dz = 1500 / freq / 4 # Step in depth direction: wavelength / 15 dr = 5 * dz # Step in range direction pos = ramRW.PosRAM(rd, ship_sd, rmax, zmax, dr, dz, zmplt) # Sound speed profile for RAM Z = sed.z cw_p = ramRW.PROF(ssp.z, ssp.c) # Water sound speed profile cb_p = ramRW.PROF(Z, sed.cp) # Bottom sound speed profile rhob_p = ramRW.PROF(Z, sed.rho) # Sea bottom density profile Ap = sed.a_p if Z[-1] < 5 * 1500 / freq: Z = np.append(Z, 3 * 1500 / freq) Ap = np.append(Ap, Ap[-1]) Z = np.append(Z, Z[-1] + 2 * 1500 / freq) Ap = np.append(Ap, 10) # Ap = sed[it].a_p attn_p = ramRW.PROF(Z, Ap) # Sea bottom attenuation profile ssp_ram = [ramRW.SSPRAM(0, cw_p, cb_p, rhob_p, attn_p)] # Write ram.in file if not os.path.exists(baseDir + "/TL/temp/theta_{:1d}".format(theta)): os.makedirs(baseDir + "/TL/temp/theta_{:1d}".format(theta)) envfil = baseDir + "/TL/temp/theta_{:1d}/ram.in".format(theta) ramRW.write_env_RAM(title, envfil, freq, pos, bathm, ssp_ram) t2 = time() #print(t2 - t1) btyFile.close() def RANDI_callRAM(baseDir, NThreads, freq, dTheta): ''' t1 = time() for theta in np.arange(0,360,5): os.chdir(baseDir + "/TL/theta_{:1d}".format(theta)) os.system(baseDir + "/ram.exe") os.chdir(baseDir) t2 = time() print(t2-t1) ''' t1 = time() func = partial(callRAM, baseDir) pool = Pool(NThreads) pool.map(func, np.arange(0, 360, dTheta)) t2 = time() #print(t2 - t1) if os.path.exists(baseDir + f"/TL/freq_{round(freq)}"): rmtree(baseDir + f"/TL/freq_{round(freq)}") os.rename(baseDir + "/TL/temp", baseDir + f"/TL/freq_{round(freq)}") def callRAM(baseDir, theta): AtBinPath = os.path.dirname(os.path.abspath(__file__))+'/at/bin' print(AtBinPath) os.chdir(baseDir + "/TL/temp/theta_{:1d}".format(theta)) os.system(AtBinPath + "/ram") os.chdir(baseDir) def RANDI_getShipNum(lat, lon, Range, dRange, theta): NRange = int(Range / dRange) #shipNum = np.random.rand(NRange) shipNum = 0.5*np.ones(NRange) return shipNum def calNoise(randiP): rr = np.arange(randiP.dRange / 2, randiP.Range, randiP.dRange) SL = RossShipSL(randiP.freq, randiP.v_ship, randiP.l_ship) S = np.power(10, SL / 10) shipNum = RANDI_getShipNum(randiP.lat, randiP.lon, randiP.Range, randiP.dRange, randiP.theta) filePath = randiP.baseDir + f"/TL/freq_{round(randiP.freq)}/theta_{round(randiP.theta)}" [r, tl] = ramRW.readTLline_RAM(filePath) r = r / 1000 I2 = np.power(10, tl / 10) I_ = interp1d(r, I2) I = I_(rr[rr < r[-1]]) noise = sum(shipNum[rr < r[-1]] * S / I) return noise def RANDI_calNL(randiP, NThreads): ''' t1 = time() theta = np.arange(0, 360, dTheta) noise1 = np.zeros(len(theta)) for i in range(len(theta)): randiP.theta = theta[i] noise1[i] = calNoise(randiP) NL1 = 10 * np.log10(sum(noise1)) t2 = time() print(t2-t1) ''' t1 = time() RANDI_P = [] for theta in np.arange(0, 360, randiP.dTheta): randiP.theta = theta RANDI_P.append(deepcopy(randiP)) pool = Pool(NThreads) noise = pool.map(calNoise, RANDI_P) NL = 10 * np.log10(sum(noise)) t2 = time() #print(t2-t1) return NL def RossShipSL(freq, v, l): if freq < 500: Lso = -10 * np.log10(np.power(10, -1.06 * np.log10(freq) - 14.34) + np.power(10, 3.32 * np.log10(freq) - 21.425)) else: Lso = 173.2 - 18 * np.log10(freq) if freq <= 28.4: df = 8.1 elif freq < 191.6: df = 22.3-9.77*np.log10(freq) else: df = 0 dl = np.power(l, 1.15) / 3643 Ls = Lso + 60*np.log10(v/12) + 20*np.log10(l/300) + df*dl + 3 return Ls def call_RANDI(ETOPO1Path, STPath, baseDir, freq, rd, lon, lat, timeType, NThreads): # 定义时间段 timeIndex = timeType # 创建类 data = DataBase(ETOPO1Path, STPath) # 设置时间段 data.set_timePeriod(timeIndex) Range = 500 # Range of sound field calculation (Unit: km) ship_sd = 6.0 # Ship source depth (Unit: m) dTheta = 5 # The angle of sector (Unit: °) dRange = 10 # The SeaDepthLim = 20 # (Unut: m) v_ship = 12 # Ship speed (Unit: kt) l_ship = 300 # Ship length (Unit: ft) randiP = RANDI_Para(baseDir, freq, lon, lat, Range, dRange, dTheta, v_ship, l_ship) RANDI_writeRAMin(baseDir, data, freq, dTheta, lat, lon, Range, rd, ship_sd, SeaDepthLim) RANDI_callRAM(baseDir, NThreads, freq, dTheta) NL = RANDI_calNL(randiP, NThreads) return NL