def get_ctd(): """ Provide the ambient CTD data Load the required CTD data from the ./test/output/test_BM54.nc dataset and include water currents. Returns ------- profile : `ambient.Profile` object An `ambient.Profile` object containing the required CTD data and currents for a `bent_plume_model` simulation. """ # Get the CTD data from the requested file nc = test_sbm.make_ctd_file() profile = ambient.Profile(nc, chem_names='all') # Add the ambient currents z = profile.nc.variables['z'][:] ua = np.zeros(z.shape) + 0.09 data = np.vstack((z, ua)).transpose() symbols = ['z', 'ua'] units = ['m', 'm/s'] comments = ['measured', 'arbitrary crossflow velocity'] profile.append(data, symbols, units, comments, 0) profile.close_nc() # Return the profile object return profile
def get_profile(): """ Create an `ambient.Profile` object from a netCDF file Create the `ambient.Profile` object needed by the `bent_plume_model` simulation from the netCDF file `./test/output/test_bm54.nc`. This function calls `test_sbm.make_ctd_file` to create the netCDF dataset before using it to create the `ambient.Profile` object. Returns ------- profile : `ambient.Profile` object Return a profile object from the BM54 CTD data """ # Get the netCDF file nc = test_sbm.make_ctd_file() # Create profile object profile = ambient.Profile(nc, chem_names='all') # Add crossflow ua = np.zeros(len(profile.z)) for i in range(len(profile.z)): ua[i] = 0.15 # Add this crossflow profile to the Profile dataset data = np.vstack((profile.z, ua)).transpose() symbols = ['z', 'ua'] units = ['m', 'm/s'] comments = ['measured', 'synthetic'] profile.append(data, symbols, units, comments, 0) # Return a profile object return profile
def profile_from_model_savefile(nc, fname, ctdname=None): """ Load the `ambient.Profile` data pointed to by the netCDF file Each netCDF model save file for the TAMOC suite models stores the file name and path to the ambient CTD data used in the simulation. This prevents the save files from having to encapsulate all of the ambient CTD data with results for every simulation run. This block of code looks for the ambient data and loads it into memory if found. Parameters ---------- nc : `netCDF4.Dataset` object The netCDF dataset object containing the saved model simulation fname : str File name of the netCDF file. This is used to get the complete path to the current directory so that the Profile data can be found. Returns ------- profile : `ambient.Profile` object The profile data as an `ambient.Profile` object. See Also -------- single_bubble_model.Model.save_sim, stratified_plume_model.Mode.save_sim, bent_plume_model.Model.save_sim Notes ----- If the profile data are not found, a message is echoed to the command line. No other warnings or errors are thrown. """ try: # Try to locate and load in the profile data nc_path = os.path.normpath(os.path.join(os.getcwd(), \ os.path.dirname(fname))) if ctdname is not None: prf_path = os.path.normpath(os.path.join(nc_path, ctdname)) else: prf_path = os.path.normpath(os.path.join(nc_path, nc.summary)) amb_data = Dataset(prf_path) profile = ambient.Profile(amb_data, chem_names='all') profile.close_nc() except RuntimeError: # Tell user that profile data read failed message = ['File not found: %s' % prf_path] message.append(' ... Continuing without profile data') warn(''.join(message)) profile = None # Send back the final profile object return profile
def test_profile_deeper(): """ Test the methods to compute buoyancy_frequency and to extend a CTD profile to greater depths. We just test the data from ctd_bm54.cnv since these methods are independent of the source of data. """ # Make sure the netCDF file for the ctd_BM54.cnv is already created by # running the test file that creates it. test_from_ctd() # Get a Profile object from this dataset __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__), 'output')) nc_file = os.path.join(__location__,'test_BM54.nc') ctd = ambient.Profile(nc_file, chem_names=['oxygen']) # Compute the buoyancy frequency at 1500 m and verify that the result is # correct N = ctd.buoyancy_frequency(1529.789, h=0.01) assert_approx_equal(N, 0.00061463758327116565, significant=6) # Record a few values to check after running the extension method T0, S0, P0, o20 = ctd.get_values(1000., ['temperature', 'salinity', 'pressure', 'oxygen']) z0 = ctd.data[:,0] # Extend the profile to 2500 m nc_file = os.path.join(__location__,'test_BM54_deeper.nc') ctd.extend_profile_deeper(2500., nc_file) # Check if the original data is preserved T1, S1, P1, o21 = ctd.get_values(1000., ['temperature', 'salinity', 'pressure', 'oxygen']) z1 = ctd.data[:,0] # Make sure the results are still right assert_approx_equal(T1, T0, significant=6) assert_approx_equal(S1, S0, significant=6) assert_approx_equal(P1, P0, significant=6) assert_approx_equal(o21, o20, significant=6) assert z1.shape[0] > z0.shape[0] assert z1[-1] == 2500. # Note that the buoyancy frequency shifts very slightly because density # is not linearly proportional to salinity. Nonetheless, the results are # close to what we want, so this method of extending the profile works # adequately. N = ctd.buoyancy_frequency(1500.) assert_approx_equal(N, 0.0006377576016247663, significant=6) N = ctd.buoyancy_frequency(2500.) assert_approx_equal(N, 0.0006146292892002274, significant=6) ctd.close_nc()
def get_blowout_model(): """ Compute the inputs defining a synthetic blowout Create the `ambient.Profile` object, `dbm.FluidMixture` object, and other parameters defining a synthetic blowout scenario. Returns ------- profile : `ambient.Profile` object Profile containing ambient CTD data oil : `dbm.FluidMixture` object A `dbm.FluidMixture` object that contains the chemical description of an oil mixture. mass_flux : ndarray An array of mass fluxes (kg/s) of each pseudo-component in the live- oil composition. z0 : float Release point of a synthetic blowout (m) Tj : float Temperature of the released fluids (K) """ # Get the CTD data from the requested file nc = test_sbm.make_ctd_file() profile = ambient.Profile(nc, chem_names='all') profile.close_nc() # Define an oil substance to use substance = { 'composition': [ 'n-hexane', '2-methylpentane', '3-methylpentane', 'neohexane', 'n-heptane', 'benzene', 'toluene', 'ethylbenzene', 'n-decane' ], 'masses': np.array([0.04, 0.07, 0.08, 0.09, 0.11, 0.12, 0.15, 0.18, 0.16]) } # Define the atmospheric gases to track ca = ['oxygen'] # Define the oil flow rate, gas to oil ratio, and orifice size q_oil = 20000. # bbl/d gor = 500. # ft^3/bbl at standard conditions z0 = 100. # release depth (m) Tj = profile.get_values(z0, 'temperature') # release temperature (K) # Import the oil with the desired gas to oil ratio oil, mass_flux = dbm_utilities.get_oil(substance, q_oil, gor, ca) return (profile, oil, mass_flux, z0, Tj)
def build_profile(fname, z, T, S, ua): """ docstring for build_profile """ # Prepare the data for insertion in the netCDF database data = np.zeros((z.shape[0], 4)) names = ['z', 'temperature', 'salinity', 'ua'] units = ['m', 'K', 'psu', 'm/s'] data[:, 0] = z.transpose() data[:, 1] = T.transpose() data[:, 2] = S.transpose() data[:, 3] = ua.transpose() # Create the netCDF file to store the data nc_file = fname summary = 'Test case for jet in crossflow' source = 'Laboratory data' sea_name = 'Laboratory' p_lat = 0. p_lon = 0. p_time = date2num(datetime(2014, 10, 15, 16, 0, 0), units='seconds since 1970-01-01 00:00:00 0:00', calendar='julian') nc = ambient.create_nc_db(nc_file, summary, source, sea_name, p_lat, p_lon, p_time) # Insert the data into the netCDF dataset comments = ['measured', 'measured', 'measured', 'measured'] nc = ambient.fill_nc_db(nc, data, names, units, comments, 0) # Compute the pressure and insert into the netCDF dataset P = ambient.compute_pressure(data[:, 0], data[:, 1], data[:, 2], 0) P_data = np.vstack((data[:, 0], P)).transpose() nc = ambient.fill_nc_db(nc, P_data, ['z', 'pressure'], ['m', 'Pa'], ['measured', 'computed'], 0) # Create an ambient.Profile object from this dataset profile = ambient.Profile(nc, chem_names='all') profile.close_nc() return profile
def get_profile(): """ Create an `ambient.Profile` object from a netCDF file Create the `ambient.Profile` object needed by the `stratified_plume_model` simulation from the netCDF file `./test/output/test_bm54.nc`. This function calls `test_sbm.make_ctd_file` to create the netCDF dataset before using it to create the `ambient.Profile` object. Returns ------- profile : `ambient.Profile` object Return a profile object from the BM54 CTD data """ # Get the netCDF file nc = test_sbm.make_ctd_file() # Return a profile object with all available chemicals in the CTD data return ambient.Profile(nc, chem_names='all')
def test_using_numpy(): """ Test the ambient data methods using only numpy This unit test repeats the tests in `test_from_txt()`, but using only the `numpy` array part of the `Profile` object instead of a netCDF dataset. """ # Get the profile objuect using netCDF datasets net_profile = test_from_txt() # Get a platform-independent path to the datafile cdat_file = os.path.join(DATA_DIR, 'C.dat') tdat_file = os.path.join(DATA_DIR, 'T.dat') # Load in the raw data using np.loadtxt C_raw = np.loadtxt(cdat_file, comments='%') T_raw = np.loadtxt(tdat_file, comments='%') # Clean the profile to remove depth reversals C_data = get_profile(C_raw, 1, 25, None, 0., 1.0256410e+01, 8.0000000e+02, 34, 2) T_data = get_profile(T_raw, 1, 25, None, 0., 1.0831721e+01, 7.9922631e+02, 34, 2) # Convert the data to standard units C_data, C_units = get_units(C_data, ['psu', 'm'], 34, 2, ['psu', 'm']) T_data, T_units = get_units(T_data, ['deg C', 'm'], 34, 2, ['K', 'm']) # Create an numpy array to hold depth and salinity var_names = ['depth', 'salinity'] var_units = ['m', 'psu'] data = np.zeros((C_data.shape[0], 3)) data[:, 0] = C_data[:, 1] data[:, 2] = C_data[:, 0] # Add the temperature data using the existing depth data data = ambient.add_data(data, 1, 'temperature', T_data, ['temperature', 'z'], T_units, ['measured', 'measured'], 1) z = data[:, 0] T = data[:, 1] S = data[:, 2] P = ambient.compute_pressure(z, T, S, 0) P_data = np.vstack((z, P)).transpose() data = ambient.add_data(data, 3, 'pressure', P_data, ['z', 'pressure'], ['m', 'Pa'], ['measured', 'measured'], 0) # Create the profile object ztsp = ['z', 'temperature', 'salinity', 'pressure'] ztsp_units = ['m', 'K', 'psu', 'Pa'] ds = ambient.Profile(data, ztsp, None, 0.01, ztsp_units, None, current=np.array([0., 0.]), current_units=['m/s', 'm/s']) # Add currents currents = np.array([[0, 0.1, 0.05], [500, 0.1, 0.05]]) var_names = ['z', 'u', 'v'] var_units = ['m', 'm/s', 'm/s'] ds.append(currents, var_names, var_units, 0) # Check if the two objects are equal check_net_numpy(net_profile, ds, currents) return ds
def get_profile_obj(nc, chem_names, chem_units): """ Check that an ambient.Profile object is created correctly and that the methods operate as expected. """ if isinstance(chem_names, str): chem_names = [chem_names] if isinstance(chem_units, str): chem_units = [chem_units] # Create the profile object prf = ambient.Profile(nc, chem_names=chem_names) # Check the chemical names and units are correct for i in range(len(chem_names)): assert prf.chem_names[i] == chem_names[i] assert prf.nchems == len(chem_names) # Check the error criteria on the interpolator assert prf.err == 0.01 # Check the get_units method name_list = ['temperature', 'salinity', 'pressure'] + chem_names unit_list = ['K', 'psu', 'Pa'] + chem_units for i in range(len(name_list)): assert prf.get_units(name_list[i])[0] == unit_list[i] units = prf.get_units(name_list) for i in range(len(name_list)): assert units[i] == unit_list[i] # Check the interpolator function ... # Pick a point in the middle of the raw dataset and read off the depth # and the values of all the variables nz = prf.nc.variables['z'].shape[0] // 2 z = prf.z[nz] y = prf.y[nz, :] # Get an interpolated set of values at this same elevation yp = prf.f(z) # Check if the results are within the level of error expected by err for i in range(len(name_list)): assert np.abs((yp[i] - y[i]) / yp[i]) <= prf.err # Next, check that the variables returned by the get_values function are # the variables we expect Tp, Sp, Pp = prf.get_values(z, ['temperature', 'salinity', 'pressure']) T = prf.nc.variables['temperature'][nz] S = prf.nc.variables['salinity'][nz] P = prf.nc.variables['pressure'][nz] assert np.abs((Tp - T) / T) <= prf.err assert np.abs((Sp - S) / S) <= prf.err assert np.abs((Pp - P) / P) <= prf.err if prf.nchems > 0: c = np.zeros(prf.nchems) cp = np.zeros(prf.nchems) for i in range(prf.nchems): c[i] = prf.nc.variables[chem_names[i]][nz] cp[i] = prf.get_values(z, chem_names[i]) assert np.abs((cp[i] - c[i]) / c[i]) <= prf.err # Test the append() method by inserting the temperature data as a new # profile, this time in degrees celsius using the variable name temp n0 = prf.nchems z = prf.nc.variables['z'][:] T = prf.nc.variables['temperature'][:] T_degC = T - 273.15 assert_array_almost_equal(T_degC + 273.15, T, decimal=6) data = np.vstack((z, T_degC)).transpose() symbols = ['z', 'temp'] units = ['m', 'deg C'] comments = ['measured', 'identical to temperature, but in deg C'] prf.append(data, symbols, units, comments, 0) # Check that the data were inserted correctly Tnc = prf.nc.variables['temp'][:] assert_array_almost_equal(Tnc, T_degC, decimal=6) assert prf.nc.variables['temp'].units == 'deg C' # Check that get_values works correctly with vector inputs for depth depths = np.linspace(prf.nc.variables['z'].valid_min, prf.nc.variables['z'].valid_max, 100) Temps = prf.get_values(depths, ['temperature', 'temp']) for i in range(len(depths)): assert_approx_equal(Temps[i, 0], Temps[i, 1] + 273.15, significant=6) # Make sure the units are returned correctly assert prf.get_units('temp')[0] == 'deg C' assert prf.nc.variables['temp'].units == 'deg C' # Check that temp is now listed as a chemical assert prf.nchems == n0 + 1 assert prf.chem_names[-1] == 'temp' # Test the API for calculating the buoyancy frequency (note that we do # not check the result, just that the function call does not raise an # error) N = prf.buoyancy_frequency(depths) N = prf.buoyancy_frequency(depths[50], h=0.1) # Send back the Profile object return prf
# Create an ambient.Profile object lake = ambient.Profile(nc, chem_names=['oxygen', 'nitrogen', 'argon']) lake.close_nc() # Return the Profile object return lake if __name__ == '__main__': # Get the ambient CTD profile data nc = '../../test/output/lake.nc' try: # Open the lake dataset as a Profile object if it exists lake = ambient.Profile(nc, chem_names=['oxygen', 'nitrogen', 'argon']) except RuntimeError: # Create the lake netCDF dataset and get the Profile object lake = get_lake_data() # Create the stratified plume model object spm = stratified_plume_model.Model(lake) # Create the dispersed phase particles composition = ['oxygen', 'nitrogen', 'argon'] yk = np.array([1.0, 0., 0.]) o2 = dbm.FluidParticle(composition, isair=True) z0 = 46. bubbles = []
def get_sim_data(): """ Get the input data to the `params.Scales` object Create an `ambient.Profile` object and a list of `stratified_plume_model.Particle` objects as the required input for the `params.Scales` object. Returns ------- profile : `ambient.Profile` object profile object from the BM54 CTD data disp_phases: list list of `stratified_plume_model.Particle` objects describing the blowout dispersed phases. z0 : float depth at the plume model origin (m) """ # Get the netCDF file nc = test_sbm.make_ctd_file() # Create a profile object with all available chemicals in the CTD data profile = ambient.Profile(nc, chem_names='all') # Create the stratified plume model object spm = stratified_plume_model.Model(profile) # Set the release conditions T0 = 273.15 + 35. # Release temperature in K R = 0.15 # Radius of leak source in m # Create the gas phase particles composition = ['methane', 'ethane', 'propane', 'oxygen'] yk = np.array([0.93, 0.05, 0.02, 0.0]) gas = dbm.FluidParticle(composition) z0 = 1000. disp_phases = [] # Larger free gas bubbles mb0 = 8. # total mass flux in kg/s de = 0.025 # bubble diameter in m lambda_1 = 0.85 disp_phases.append( stratified_plume_model.particle_from_mb0(profile, z0, gas, yk, mb0, de, lambda_1, T0)) # Smaller free gas bubbles (note, it is not necessary to have more than # one bubble size) mb0 = 2. # total mass flux in kg/s de = 0.0075 # bubble diameter in m lambda_1 = 0.9 disp_phases.append( stratified_plume_model.particle_from_mb0(profile, z0, gas, yk, mb0, de, lambda_1, T0)) # Liquid hydrocarbon. This could either be a dissolving phase (mixture # of liquid phases) or an inert phase. We demonstrate here the simple # case of an inert oil phase oil = dbm.InsolubleParticle(True, True, rho_p=890., gamma=30., beta=0.0007, co=2.90075e-9) mb0 = 10. # total mass flux in kg/s de = 0.004 # bubble diameter in m lambda_1 = 0.9 disp_phases.append( stratified_plume_model.particle_from_mb0(profile, z0, oil, np.array([1.]), mb0, de, lambda_1, T0)) # Return the simulation data return (profile, disp_phases, z0)
def create_ambient_profile(data, labels, units, comments, nc_name, summary, source, sea_name, p_lat, p_lon, p_time, ca=[]): """ Create an ambient Profile object from given data Create an ambient.Profile object using the given CTD and current data. This function performs some standard operations to this data (unit conversion, computation of pressure, insertion of concentrations for dissolved gases, etc.) and returns the working ambient.Profile object. The idea behind this function is to separate data manipulation and creation of the ambient.Profile object from fetching of the data itself. Parameters ---------- data : np.array Array of the ambient ocean data to write to the CTD file. The contents and dimensions of this data are specified in the labels and units lists, below. labels : list List of string names of each variable in the data array. units : list List of units as strings for each variable in the data array. comments : list List of comments as strings that explain the types of data in the data array. Typical comments include 'measured', 'modeled', or 'computed'. nc_name : str String containing the file path and file name to use when creating the netCDF4 dataset that will contain this data. summary : str String describing the simulation for which this data will be used. source : str String documenting the source of the ambient ocean data provided. sea_name : str NC-compliant name for the ocean water body as a string. p_lat : float Latitude (deg) p_lon : float Longitude, negative is west of 0 (deg) p_time : netCDF4 time format Date and time of the CTD data using netCDF4.date2num(). ca : list, default=[] List of gases for which to compute a standard dissolved gas profile; choices are 'nitrogen', 'oxygen', 'argon', and 'carbon_dioxide'. Returns ------- profile : ambient.Profile Returns an ambient.Profile object for manipulating ambient water column data in TAMOC. """ # Convert the data to standard units data, units = ambient.convert_units(data, units) # Create an empty netCDF4-classic datast to store this CTD data nc = ambient.create_nc_db(nc_name, summary, source, sea_name, p_lat, p_lon, p_time) # Put the CTD and current profile data into the ambient netCDF file nc = ambient.fill_nc_db(nc, data, labels, units, comments, 0) # Compute and insert the pressure data z = nc.variables['z'][:] T = nc.variables['temperature'][:] S = nc.variables['salinity'][:] P = ambient.compute_pressure(z, T, S, 0) P_data = np.vstack((z, P)).transpose() nc = ambient.fill_nc_db(nc, P_data, ['z', 'pressure'], ['m', 'Pa'], ['measured', 'computed'], 0) # Use this netCDF file to create an ambient object profile = ambient.Profile( nc, ztsp=['z', 'temperature', 'salinity', 'pressure', 'ua', 'va']) # Compute dissolved gas profiles to add to this dataset if len(ca) > 0: # Create a gas mixture object for air gases = ['nitrogen', 'oxygen', 'argon', 'carbon_dioxide'] air = dbm.FluidMixture(gases) yk = np.array([0.78084, 0.20946, 0.009340, 0.00036]) m = air.masses(yk) # Set atmospheric conditions Pa = 101325. # Compute the desired concentrations for i in range(len(ca)): # Initialize a dataset of concentration data conc = np.zeros(len(profile.z)) # Compute the concentrations at each depth for j in range(len(conc)): # Get the local water column properties T, S, P = profile.get_values( profile.z[j], ['temperature', 'salinity', 'pressure']) # Compute the gas solubility at this temperature and salinity # at the sea surface Cs = air.solubility(m, T, Pa, S)[0, :] # Adjust the solubility to the present depth Cs = Cs * seawater.density(T, S, P) / \ seawater.density(T, S, 101325.) # Extract the right chemical conc[j] = Cs[gases.index(ca[i])] # Add this computed dissolved gas to the Profile dataset data = np.vstack((profile.z, conc)).transpose() symbols = ['z', ca[i]] units = ['m', 'kg/m^3'] comments = ['measured', 'computed from CTD data'] profile.append(data, symbols, units, comments, 0) # Close the netCDF dataset profile.close_nc() # Return the profile object return profile
def get_ctd_profile(): """ Load the ASCII CTD Data into an `ambient.Profile` object. This function performs the steps in ./profile_from_ctd.py to read in the CTD data and create a Profile object. This is the data set that will be used to demonstrate how to append data to a Profile object. """ # Get the path to the input file __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__), '../../tamoc/data')) dat_file = os.path.join(__location__, 'ctd_BM54.cnv') # Load in the data using numpy.loadtxt raw = np.loadtxt(dat_file, comments='#', skiprows=175, usecols=(0, 1, 3, 8, 9, 10, 12)) # Describe the organization of the data in raw. var_names = [ 'temperature', 'pressure', 'wetlab_fluorescence', 'z', 'salinity', 'density', 'oxygen' ] var_units = ['deg C', 'db', 'mg/m^3', 'm', 'psu', 'kg/m^3', 'mg/l'] z_col = 3 # Clean the profile to remove reversals in the depth coordinate data = ambient.extract_profile(raw, z_col, 50.0) # Convert the profile data to standard units in TAMOC profile, units = ambient.convert_units(data, var_units) # Create an empty netCDF4-classic dataset to store this CTD data __location__ = os.path.realpath( os.path.join(os.getcwd(), os.path.dirname(__file__), '../../test/output')) nc_file = os.path.join(__location__, 'BM54.nc') summary = 'Dataset created by profile_from_ctd in the ./bin directory' \ + ' of TAMOC' source = 'R/V Brooks McCall, station BM54' sea_name = 'Gulf of Mexico' p_lat = 28.0 + 43.945 / 60.0 p_lon = 360 - (88.0 + 22.607 / 60.0) p_time = date2num(datetime(2010, 5, 30, 18, 22, 12), units='seconds since 1970-01-01 00:00:00 0:00', calendar='julian') nc = ambient.create_nc_db(nc_file, summary, source, sea_name, p_lat, p_lon, p_time) # Insert the CTD data into the netCDF dataset comments = ['measured'] * len(var_names) nc = ambient.fill_nc_db(nc, profile, var_names, units, comments, z_col) # Create an ambient.Profile object for this dataset bm54 = ambient.Profile(nc, chem_names=['oxygen']) # Return the Profile object return bm54
source = 'R/V Brooks McCall, station BM54' sea_name = 'Gulf of Mexico' p_lat = 28.0 + 43.945 / 60.0 p_lon = 360 - (88.0 + 22.607 / 60.0) p_time = date2num(datetime(2010, 5, 30, 18, 22, 12), units='seconds since 1970-01-01 00:00:00 0:00', calendar='julian') nc = ambient.create_nc_db(nc_file, summary, source, sea_name, p_lat, p_lon, p_time) # Insert the CTD data into the netCDF dataset comments = ['measured'] * len(var_names) nc = ambient.fill_nc_db(nc, profile, var_names, units, comments, z_col) # Create an ambient.Profile object for this dataset bm54 = ambient.Profile(nc, chem_names=['oxygen'], err=0.00001) # Close the netCDF dataset bm54.nc.close() # Since the netCDF file is now fully stored on the hard drive in the # correct format, we can initialize an ambient.Profile object directly # from the netCDF file bm54 = ambient.Profile(nc_file, chem_names='all') # Plot the density profile using the interpolation function z = np.linspace(bm54.nc.variables['z'].valid_min, bm54.nc.variables['z'].valid_max, 250) rho = np.zeros(z.shape) T = np.zeros(z.shape)
def get_lake_data(): """ Create the netCDF dataset of CTD data for a lake simulation Creates the ambient.Profile object and netCDF dataset of CTD data for a lake simualtion from the `./data/lake.dat` text file, digitized from the data in McGinnis et al. (2002) for Lake Hallwil. """ # Read in the lake CTD data fname = '../../tamoc/data/lake.dat' raw = np.loadtxt(fname, skiprows=9) variables = ['z', 'temperature', 'salinity', 'oxygen'] units = ['m', 'deg C', 'psu', 'kg/m^3'] # Convert the units to mks profile, units = ambient.convert_units(raw, units) # Calculate the pressure data P = ambient.compute_pressure(profile[:, 0], profile[:, 1], profile[:, 2], 0) profile = np.hstack((profile, np.atleast_2d(P).transpose())) variables = variables + ['pressure'] units = units + ['Pa'] # Set up a netCDF dataset object summary = 'Default lake.dat dataset provided by TAMOC' source = 'Lake CTD data digitized from figures in McGinnis et al. 2004' sea_name = 'Lake Hallwil, Switzerland' lat = 47.277166666666666 lon = 8.217294444444445 date = datetime(2002, 7, 18) t_units = 'seconds since 1970-01-01 00:00:00 0:00' calendar = 'julian' time = date2num(date, units=t_units, calendar=calendar) nc = ambient.create_nc_db('../../test/output/lake.nc', summary, source, sea_name, lat, lon, time) # Insert the measured data comments = ['digitized from measured data'] * 4 comments = comments + ['computed from z, T, S'] nc = ambient.fill_nc_db(nc, profile, variables, units, comments, 0) # Insert an additional column with data for nitrogen and argon equal to # their saturation concentrations at the free surface. composition = ['nitrogen', 'oxygen', 'argon'] yk = np.array([0.78084, 0.209476, 0.009684]) air = dbm.FluidMixture(composition) m = air.masses(yk) Cs = air.solubility(m, profile[0, 1], 101325., profile[0, 2]) N2 = np.zeros((profile.shape[0], 1)) Ar = np.zeros((profile.shape[0], 1)) N2 = N2 + Cs[0, 0] Ar = Ar + Cs[0, 2] z = np.atleast_2d(profile[:, 0]).transpose() comments = ['calculated potential saturation value'] * 3 nc = ambient.fill_nc_db(nc, np.hstack( (z, N2, Ar)), ['z', 'nitrogen', 'argon'], ['m', 'kg/m^3', 'kg/m^3'], comments, 0) # Create an ambient.Profile object lake = ambient.Profile(nc, chem_names=['oxygen', 'nitrogen', 'argon']) lake.close_nc() # Return the Profile object return lake
nc = ambient.fill_nc_db(nc, C_profile, ['salinity', 'z'], C_units, comments, 1) nc = ambient.fill_nc_db(nc, T_profile, ['temperature', 'z'], T_units, comments, 1) # Calculate and insert the pressure data z = nc.variables['z'][:] T = nc.variables['temperature'][:] S = nc.variables['salinity'][:] P = ambient.compute_pressure(z, T, S, 0) P_data = np.vstack((z, P)).transpose() nc = ambient.fill_nc_db(nc, P_data, ['z', 'pressure'], ['m', 'Pa'], ['measured', 'computed'], 0) # Create an ambient.Profile object for this dataset ds = ambient.Profile(nc) # Close the netCDF dataset ds.nc.close() # Since the netCDF file is now fully stored on the hard drive in the # correct format, we can initialize an ambient.Profile object directly # from the netCDF file ds = ambient.Profile(nc_file, chem_names='all') # Plot the density profile using the interpolation function z = np.linspace(ds.nc.variables['z'].valid_min, ds.nc.variables['z'].valid_max, 250) rho = np.zeros(z.shape) tsp = ds.get_values(z, ['temperature', 'salinity', 'pressure']) for i in range(len(z)):
def get_ambient_profile(water, current, **kwargs): """ Create an `ambient.Profile` object from the given ambient data Based on the water column information provided, make an appropriate choice and create the `ambient.Profile` object required for a `tamoc` simulation. Parameters ---------- water : various Data describing the ambient water temperature and salinity profile. See Notes below for details. current : various Data describing the ambient current velocity profile. See Notes below for details. **kwargs : dict Dictionary of optional keyword arguments that can be used when creating an ambient.Profile object from a text file. Optional arguments include: summary : str String describing the simulation for which this data will be used. source : str String documenting the source of the ambient ocean data provided. sea_name : str NC-compliant name for the ocean water body as a string. p_lat : float Latitude (deg) p_lon : float Longitude, negative is west of 0 (deg) p_time : netCDF4 time format Date and time of the CTD data using netCDF4.date2num(). ca : list, default=[] List of dissolved atmospheric gases to include in the ambient ocean data as a derived concentration; choices are 'nitrogen', 'oxygen', 'argon', and 'carbon_dioxide'. If any of these arguments are not passed, default values will be assigned by this function. Notes ----- The `water` variable contains information about the ambient temperature and salinity profile. Possible choices for `water` include the following: water : None Indicates that we have no information about the ambient temperature or salinity. In this case, the model will import data for the world-ocean average. water : dict If we only know the water temperature and salinity at the surface, this may be passed through a dictionary with keywords `temperature` and `salinity`. In this case, the model will import data for the world-ocean average and adjust the data to have the given temperature and salinity at the surface. water : 'netCDF4.Dataset' object If a 'netCDF4.Dataset' object already contains the ambient CTD data in a format appropriate for the `ambient.Profile` object, then this can be passed. In this case, it is assumed that the dataset includes the currents; hence, the `currents` variable will be ignored. water : `ambient.Profile` object If we already created our own ambient Profile object, then this object can be used directly. water = str If we stored the water column profile in a file, we may provide the file path to this file via the string stored in water. If this string ends in '.nc', it is assumed that this file contains a netCDF4 dataset. Otherwise, this file should contain columns in the following order: depth (m), temperature (deg C), salinity (psu), velocity in the x-direction (m/s), velocity in the y-direction (m/s). Since this option includes the currents, the current variable will be ignored in this case. A comment string of `#` may be used in the text file. The `current` variable contains information about the ambient current profile. Possible choices for `current` include the following: current : float This is assumed to be the current velocity along the x-axis and will be uniform over the depth current : ndarray This is assumed to contain the current velocity in the x- and y- (and optionally also z-) directions. If this is a one-dimensional array, then these currents will be assumed to be uniform over the depth. If this is a multi-dimensional array, then these values as assumed to contain a profile of data, with the depth (m) as the first column of data. """ NoneType = type(None) done = False # Extract the temperature and salinity data if isinstance(water, NoneType): # Use the world-ocean average T(z) and S(z) data = None if isinstance(water, dict): # Get the water temperature and salinity at the surface Ts = water['temperature'] Ss = water['salinity'] # Create a data array of depth, temperature, and salinity data = np.array([0., Ts, Ss]) if isinstance(water, Dataset): # A netCDF4 Dataset containing all of the profile data is stored # in water. Use that to create the Profile object profile = ambient.Profile(water) done = True if isinstance(water, ambient.Profile): profile = water done = True elif isinstance(water, str) or isinstance(water, unicode): if water[-3:] == '.nc': # Water contains a path to a netCDF4 dataset. Use this to # create the Profile object profile = ambient.Profile(water) done = True else: # This must be a relative path to a text file fname = water x0 = np.array([0., 0.]) try: ca = kwargs['ca'] except: ca = [] try: summary = kwargs['summary'] except: summary = 'CTD text file stored in: ' + water try: source = kwargs['source'] except: source = 'tamoc.blowout.get_ctd_from_txt()' try: sea_name = kwargs['sea_name'] except: sea_name = 'Text File' try: p_lon = kwargs['p_lon'] except: p_lon = x0[0] try: p_lat = kwargs['p_lat'] except: p_lat = x0[1] try: p_time = kwargs['p_time'] except: p_time = date2num( datetime.now(), units='seconds since 1970-01-01 00:00:00 0:00', calendar='julian') profile = get_ctd_from_txt(fname, summary, source, sea_name, p_lat, p_lon, p_time, ca) done = True # Create the `ambient.Profile` object if not done: profile = ambient.Profile(data, current=current, current_units='m/s') # Returen the profile return profile
# Insert the CTD data into the netCDF dataset comments = ['synthetic'] * 3 nc = ambient.fill_nc_db(nc, profile, ['z', 'temperature', 'salinity'], ['m', 'K', 'psu'], comments, 0) # Calculate and insert the pressure data z = nc.variables['z'][:] T = nc.variables['temperature'][:] S = nc.variables['salinity'][:] P = ambient.compute_pressure(z, T, S, 0) P_data = np.vstack((z, P)).transpose() nc = ambient.fill_nc_db(nc, P_data, ['z', 'pressure'], ['m', 'Pa'], ['measured', 'computed'], 0) # Create an ambient.Profile object for this dataset lab = ambient.Profile(nc) # Close the netCDF dataset lab.nc.close() # Since the netCDF file is now fully stored on the hard drive in the # correct format, we can initialize an ambient.Profile object directly # from the netCDF file lab = ambient.Profile(nc_file) # Plot the density profile using the interpolation function z = np.linspace(lab.nc.variables['z'].valid_min, lab.nc.variables['z'].valid_max, 250) rho = np.zeros(z.shape) tsp = lab.get_values(z, ['temperature', 'salinity', 'pressure']) for i in range(len(z)):
from tamoc import ambient from tamoc import dbm from tamoc import stratified_plume_model from datetime import datetime from netCDF4 import date2num import numpy as np if __name__ == '__main__': # Get the ambient CTD profile data nc = '../../test/output/test_BM54.nc' try: # Open the lake dataset as a Profile object if it exists ctd = ambient.Profile(nc, chem_names='all') except RuntimeError: # Tell the user to create the dataset print('CTD data not available; run test cases in ./test first.') # Create the stratified plume model object spm = stratified_plume_model.Model(ctd) # Set the release conditions T0 = 273.15 + 35. # Release temperature in K R = 0.15 # Radius of leak source in m # Create the gas phase particles composition = ['methane', 'ethane', 'propane', 'oxygen'] yk = np.array([0.93, 0.05, 0.02, 0.0])
def get_profile(self, nc_name, fname, u_a, v_a, w_a, depths): """ Read in the ambient CTD data Read in the CTD data specified by API for all test cases. Append the velocity information to the CTD file. Parameters ---------- nc_name : str Name to call the netCDF4 dataset. u_a : float Crossflow velocity for this test case (m/s). Returns ------- profile : `ambient.Profile` object Returns an `ambient.Profile` object of the ambient CTD and velocity information """ # Get the ambient CTD data names = ['z', 'temperature', 'salinity', 'oxygen'] units = ['m', 'deg C', 'psu', 'mmol/m^3'] data = np.loadtxt(fname, comments='%') # Convert the data to standard units M_o2 = 31.9988 / 1000. # kg/mol data[:, 3] = data[:, 3] / 1000. * M_o2 units[3] = 'kg/m^3' data, units = ambient.convert_units(data, units) # Create an empty netCDF4 dataset to store the CTD dat summary = 'Global horizontal mean hydrographic and oxygen data' source = 'Taken from page 226 of Sarmiento and Gruber' sea_name = 'Global' p_lat = 0. p_lon = 0. p_time = date2num(datetime(1998, 1, 1, 1, 0, 0), units='seconds since 1970-01-01 00:00:00 0:00', calendar='julian') nc = ambient.create_nc_db(nc_name, summary, source, sea_name, p_lat, p_lon, p_time) # Insert the data into the netCDF dataset comments = ['average', 'average', 'average', 'average'] nc = ambient.fill_nc_db(nc, data, names, units, comments, 0) # Compute the pressure and insert into the netCDF dataset P = ambient.compute_pressure(data[:, 0], data[:, 1], data[:, 2], 0) P_data = np.vstack((data[:, 0], P)).transpose() nc = ambient.fill_nc_db(nc, P_data, ['z', 'pressure'], ['m', 'Pa'], ['average', 'computed'], 0) # Create an ambient.Profile object from this dataset profile = ambient.Profile(nc, chem_names='all') # Force the max depth to model # depths[-1] = profile.z_max # Add the crossflow velocity print '******************' print depths print '******************' u_crossflow = np.zeros((len(depths), 2)) u_crossflow[:, 0] = depths if u_a.shape != depths.shape: u_crossflow[:, 1] = np.linspace(u_a[0], u_a[-1], len(depths)) else: u_crossflow[:, 1] = u_a symbols = ['z', 'ua'] units = ['m', 'm/s'] comments = ['provided', 'provided'] profile.append(u_crossflow, symbols, units, comments, 0) v_crossflow = np.zeros((len(depths), 2)) v_crossflow[:, 0] = depths if v_a.shape != depths.shape: v_crossflow[:, 1] = np.linspace(v_a[0], v_a[-1], len(depths)) else: v_crossflow[:, 1] = v_a symbols = ['z', 'va'] units = ['m', 'm/s'] comments = ['provided', 'provided'] profile.append(v_crossflow, symbols, units, comments, 0) w_crossflow = np.zeros((len(depths), 2)) w_crossflow[:, 0] = depths if w_a.shape != depths.shape: w_crossflow[:, 1] = np.linspace(w_a[0], w_a[-1], len(depths)) else: w_crossflow[:, 1] = w_a symbols = ['z', 'wa'] units = ['m', 'm/s'] comments = ['provided', 'provided'] profile.append(w_crossflow, symbols, units, comments, 0) # Finalize the profile (close the nc file) profile.close_nc() # Return the final profile return profile
nc_file = os.path.join(__location__, 'roms.nc') # Select the indices to the point in the ROMS output where we want to # extract the profile t_idx = 0 j_idx = 400 i_idx = 420 # Open the ROMS output file and create the TAMOC input file (nc, dat_file) = ambient.get_nc_db_from_roms(dat_file, nc_file, t_idx, j_idx, i_idx, ['dye_01', 'dye_02']) dat_file.close() # Create an ambient.Profile object for this dataset roms = ambient.Profile(nc, chem_names=['dye_01', 'dye_02']) # Close the netCDF dataset roms.nc.close() # Since the netCDF file is now fully stored on the hard drive in the # correct format, we can initialize an ambient.Profile object directly # from the netCDF file roms = ambient.Profile(nc_file, chem_names='all') # Plot the density profile using the interpolation function z = np.linspace(roms.nc.variables['z'].valid_min, roms.nc.variables['z'].valid_max, 250) rho = np.zeros(z.shape) tsp = roms.get_values(z, ['temperature', 'salinity', 'pressure']) for i in range(len(z)):
warnings.filterwarnings("ignore") if __name__ == '__main__': print('\n---------------------------------------------------------------') print('Demonstration using the Model class in the') print('particle_size_models module of TAMOC for a ') print('synthetic subsea accidental blowout case') print('---------------------------------------------------------------') # The inputs for a particle_size_models.Model simulation are similar to # those of the bent_plume_model. We start by defining the ambient CTD # data. Here, we will use the world-ocean average data distributed with # TAMOC. Since the particle_size_models do not use ambient current data, # we will ignore that. profile = ambient.Profile(None) # For the particle_size_models.Model object, we need to create a # dbm.FluidMixture object. Here, we make use of the dbm_utilities # to create synthetic blowout data. # Start by defining a substance substance = { 'composition': [ 'n-hexane', '2-methylpentane', '3-methylpentane', 'neohexane', 'n-heptane', 'benzene', 'toluene', 'ethylbenzene', 'n-decane' ], 'masses': np.array([0.04, 0.07, 0.08, 0.09, 0.11, 0.12, 0.15, 0.18, 0.16]) }