import os from multiprocessing import Pool from functools import partial from time import time from shutil import rmtree import numpy as np from scipy.interpolate import interp1d from copy import deepcopy from pyat import ramRW_new as ramRW from pyat.DataBase import DataBase,soundSpeed 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 = 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