Source code for bemio.io.wamit

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
'''This moduel provides functionality to read and interact with WAMIT simulation output data
'''
import os

import numpy as np

from bemio.data_structures import bem

[docs]class WamitOutput(object): '''Class to read and interact with WAMIT simulation data Parameters: out_file : str Name of the wamit .out output file. In order to read scattering and Froud-Krylof forces the .3sc (scatterin) and .3fk (Froud-Krylof) coefficinet files must have the same base name as the .out file. density : float, optional Water density used to scale the hydrodynamic coefficient data gravity : float, optional Acceleration due to gravity used to scale the hydrodynamic coefficient dataaaa scale : bool, optional Boolean value to determine if the hydrodynamic data is scaled. See the bemio.data_structures.bem.scale function for more information Examples The user can create a WamitOutput data object directily as show below, or the bemio.io.wamit.read function can be used. The following example assumes there is a WAMIT output file named `wamit.out`. >>> wamit_data = WamitOtuput(out_file=wamit.out) ''' def __init__(self, out_file, density=1000., gravity=9.81, scale=False): self.files = bem.generate_file_names(out_file) self.files['3sc'] = self.files['base_name'] + '.3sc' self.files['3fk'] = self.files['base_name'] + '.3fk' self.rho = density self.g = gravity self.body = {} self.scaled_at_read = scale self.scaled = False self._read() def _read(self): '''Internal function to read WAMIT output file into the class. that is called during __init__ ''' print '\nReading the WAMIT results in the ' + self.files['out'] + ' file' with open(self.files['out'],'rU') as fid: raw = fid.readlines() code = 'WAMIT' num_bodies = 0 # Total number of bodies bod_count = 0 # Counter for bodies T = [] cg = {} cb = {} name = {} disp_vol = {} k = {} wave_dir = [] empty_line = '\n' for i, line in enumerate(raw): if "POTEN run date and starting time:" in line: skip = 2 data = raw[i+skip] count = 0 while data != empty_line: if float(data.split()[0]) == 0. or float(data.split()[0]) == -1.: count += 1 data = raw[i+count+skip] else: count += 1 T.append(float(data.split()[0])) data = raw[i+count+skip] if "Wave Heading (deg)" in line: wave_dir.append(float(line.split()[-1])) if 'Water depth:' in line: water_depth = raw[i].split()[2] try: water_depth = np.float(water_depth) except: pass # If there is one body in the WAMIT run if "Input from Geometric Data File:" in line: num_bodies = 1 name[0] = raw[i].split()[-1] # If there are two bodies in the WAMIT run if "Input from Geometric Data Files:" in line: for j in xrange(20): # look for bodies within the next 20 lines if "N=" in raw[i+j]: num_bodies += 1 name[num_bodies-1] = raw[i+j].split()[-1] # Read the body positions if "Total panels:" in line or "NPATCH:" in line: for j in xrange(15): # look for position within the next 15 lines - will only work for wamit files of about 5 bodies if 'XBODY =' in raw[i+j]: ''' Note that this is the XBOD YBOD ZBOD defined in the wamit .out file, not the cg as defined in the wamit file ''' temp = raw[i+j].split() cg[bod_count] = np.array([temp[2],temp[5],temp[8]]).astype(float) if 'Volumes (VOLX,VOLY,VOLZ):' in raw[i+j]: temp = raw[i+j].split() disp_vol[bod_count] = float(temp[-1]) if 'Center of Buoyancy (Xb,Yb,Zb):' in raw[i+j]: temp = raw[i+j].split() cb[bod_count] = np.array([temp[-3],temp[-2],temp[-1]]).astype(float) if 'C(3,3),C(3,4),C(3,5):' in raw[i+j]: temp = np.zeros([6,6]) temp2 = raw[i+j].split() temp[2,2] = np.float(temp2[1]) temp[2,3] = np.float(temp2[2]) temp[2,4] = np.float(temp2[3]) temp[3,2] = temp[2,3] temp[4,2] = temp[2,4] temp2 = raw[i+j+1].split() temp[3,3] = np.float(temp2[1]) temp[3,4] = np.float(temp2[2]) temp[3,5] = np.float(temp2[3]) temp[4,3] = temp[3,4] temp[5,3] = temp[3,5] temp2 = raw[i+j+2].split() temp[4,4] = np.float(temp2[1]) temp[4,5] = np.float(temp2[2]) temp[5,4] = temp[4,5] k[bod_count] = temp bod_count += 1 # Put things into numpy arrays T = np.array(T).astype(float) wave_dir = np.array(wave_dir).astype(float) # Only select the wave headings once temp = 999999 temp_wave_dir = [] count = 0 while temp != wave_dir[0]: count += 1 temp_wave_dir.append(wave_dir[count-1]) temp = wave_dir[count] wave_dir = np.array(temp_wave_dir).astype(float) # Read added mass and rad damping count_freq = 0 am_all = np.zeros([6*num_bodies,6*num_bodies,T.size]) rd_all = am_all.copy() am_inf = np.zeros([6*num_bodies,6*num_bodies]) am_zero = am_inf.copy() for i, line in enumerate(raw): # Read inf freq added mass if "Wave period = zero" in line: count = 7 temp_line = raw[count+i] while temp_line != empty_line: am_inf[int(temp_line.split()[0])-1,int(temp_line.split()[1])-1] = temp_line.split()[2] count += 1 temp_line = raw[count+i] # Read zero freq added mass if "Wave period = infinite" in line: count = 7 temp_line = raw[count+i] while temp_line != empty_line: am_zero[int(temp_line.split()[0])-1,int(temp_line.split()[1])-1] = temp_line.split()[2] count += 1 temp_line = raw[count+i] # Read freq dependent added mass and rad damping if "Wave period (sec) =" in line: count = 7 temp_line = raw[count+i] while temp_line != empty_line: am_all[int(temp_line.split()[0])-1,int(temp_line.split()[1])-1,count_freq] = temp_line.split()[2] rd_all[int(temp_line.split()[0])-1,int(temp_line.split()[1])-1,count_freq] = temp_line.split()[3] count += 1 temp_line = raw[count+i] count_freq += 1 # Terribly complicated code to read excitation forces and phases, RAOs, etc ex_all = np.zeros([6*num_bodies,wave_dir.size,T.size]) phase_all = ex_all.copy() rao_all = ex_all.copy() rao_phase_all = ex_all.copy() ssy_all = ex_all.copy() ssy_phase_all = ex_all.copy() haskind_all = ex_all.copy() haskind_phase_all = ex_all.copy() count_diff2 = 0 count_rao2 = 0 count_ssy2 = 0 count_haskind2 = 0 for i, line in enumerate(raw): count_diff = 0 count_rao = 0 count_ssy = 0 count_haskind = 0 if "DIFFRACTION EXCITING FORCES AND MOMENTS" in line: count_diff += 1 count_diff2 += 1 count_wave_dir = 0 count = 0 while count_wave_dir < wave_dir.size: count += 1 if "Wave Heading (deg) :" in raw[i+count_diff + count]: count_wave_dir += 1 temp_line = raw[i+count_diff+count+4] count2 = 0 while temp_line != empty_line: count2 += 1 ex_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_diff2-1] = float(temp_line.split()[1]) phase_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_diff2-1] = float(temp_line.split()[2]) temp_line = raw[i+count_diff+count+4+count2] if "RESPONSE AMPLITUDE OPERATORS" in line: count_rao += 1 count_rao2 += 1 count_wave_dir = 0 count = 0 while count_wave_dir < wave_dir.size: count += 1 if "Wave Heading (deg) :" in raw[i+count_rao + count]: count_wave_dir += 1 temp_line = raw[i+count_rao+count+4] count2 = 0 while temp_line != empty_line: count2 += 1 rao_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_rao2-1] = float(temp_line.split()[1]) rao_phase_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_rao2-1] = float(temp_line.split()[2]) temp_line = raw[i+count_rao+count+4+count2] if "HASKIND EXCITING FORCES AND MOMENTS" in line: count_haskind += 1 count_haskind2 += 1 count_wave_dir = 0 count = 0 while count_wave_dir < wave_dir.size: count += 1 if "Wave Heading (deg) :" in raw[i+count_haskind + count]: count_wave_dir += 1 temp_line = raw[i+count_ssy+count+4] count2 = 0 while temp_line != empty_line: count2 += 1 haskind_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_haskind2-1] = float(temp_line.split()[1]) haskind_phase_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_haskind2-1] = float(temp_line.split()[2]) temp_line = raw[i+count_ssy+count+4+count2] if "SURGE, SWAY & YAW DRIFT FORCES (Momentum Conservation)" in line: count_ssy += 1 count_ssy2 += 1 count_wave_dir = 0 count = 0 while count_wave_dir < wave_dir.size: count += 1 if "Wave Heading (deg) :" in raw[i+count_ssy + count]: count_wave_dir += 1 temp_line = raw[i+count_ssy+count+4] count2 = 0 while temp_line != empty_line: count2 += 1 ssy_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_ssy2-1] = float(temp_line.split()[1]) ssy_phase_all[int(temp_line.split()[0])-1,count_wave_dir-1,count_ssy2-1] = float(temp_line.split()[2]) temp_line = raw[i+count_ssy+count+4+count2] if os.path.exists(self.files['3sc']): sc_re = np.zeros([6*num_bodies,wave_dir.size,T.size]) sc_im = sc_re.copy() sc_phase = sc_re.copy() sc_mag = sc_re.copy() scattering = np.loadtxt(self.files['3sc'],skiprows=1) line_count = 0 for freq_n in xrange(T.size): for beta_n in xrange(wave_dir.size): wave_dir_hold = scattering[line_count][1] while line_count < scattering.shape[0] and scattering[line_count][1] == wave_dir_hold: comp = int(scattering[line_count][2])-1 sc_mag[comp,beta_n,freq_n] = scattering[line_count][3] sc_phase[comp,beta_n,freq_n] = scattering[line_count][4] sc_re[comp,beta_n,freq_n] = scattering[line_count][5] sc_im[comp,beta_n,freq_n] = scattering[line_count][6] wave_dir_hold = scattering[line_count][1] line_count += 1 else: print '\tThe file ' + self.files['3sc'] + ' does not exist... not reading scattering coefficients.' if os.path.exists(self.files['3fk']): fk_re = np.zeros([6*num_bodies,wave_dir.size,T.size]) fk_im = fk_re.copy() fk_phase = fk_re.copy() fk_mag = fk_re.copy() fk = np.loadtxt(self.files['3fk'],skiprows=1) line_count = 0 for freq_n in xrange(T.size): for beta_n in xrange(wave_dir.size): wave_dir_hold = fk[line_count][1] while line_count < fk.shape[0] and fk[line_count][1] == wave_dir_hold: comp = int(fk[line_count][2])-1 fk_mag[comp,beta_n,freq_n] = fk[line_count][3] fk_phase[comp,beta_n,freq_n] = fk[line_count][4] fk_re[comp,beta_n,freq_n] = fk[line_count][5] fk_im[comp,beta_n,freq_n] = fk[line_count][6] wave_dir_hold = scattering[line_count][1] line_count += 1 else: print '\tThe file ' + self.files['3fk'] + ' does not exist... not reading froud krylof coefficients.' # Load data into the hydrodata structure for i in xrange(num_bodies): self.body[i] = bem.HydrodynamicData() self.body[i].scaled = self.scaled self.body[i].g = self.g self.body[i].rho = self.rho self.body[i].body_num = i self.body[i].name = name[i][0:-4] self.body[i].water_depth = water_depth self.body[i].num_bodies = num_bodies self.body[i].cg = cg[i] self.body[i].cb = cb[i] self.body[i].k = k[i] self.body[i].disp_vol = disp_vol[i] self.body[i].wave_dir = wave_dir self.body[i].T = T self.body[i].w = 2.0*np.pi/self.body[i].T if 'am_inf' in locals(): self.body[i].am.inf = am_inf[6*i:6+6*i,:] else: self.body[i].am.inf = np.nan*np.zeros([6*num_bodies,6*num_bodies,self.body[i].T.size]) print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain infinite frequency added mass coefficients' if 'am_zero' in locals(): self.body[i].am.zero = am_zero[6*i:6+6*i,:] else: self.body[i].am.zero = np.nan*np.zeros([6*num_bodies,6*num_bodies,self.body[i].T.size]) print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain zero frequency added mass coefficients' if 'am_all' in locals(): self.body[i].am.all = am_all[6*i:6+6*i,:,:] else: self.body[i].am.all = np.nan*np.zeros([6*num_bodies,6*num_bodies,self.body[i].T.size]) print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain any frequency dependent added mass coefficients' if 'rd_all' in locals(): self.body[i].rd.all = rd_all[6*i:6+6*i,:,:] else: self.body[i].rd.all = np.nan*np.zeros([6*num_bodies,6*num_bodies,self.body[i].T.size]) print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain any frequency dependent radiation damping coefficients' if 'ex_all' in locals(): self.body[i].ex.mag = ex_all[6*i:6+6*i,:,:] self.body[i].ex.phase = np.deg2rad(phase_all[6*i:6+6*i,:,:]) self.body[i].ex.re = self.body[i].ex.mag*np.cos(self.body[i].ex.phase) self.body[i].ex.im = self.body[i].ex.mag*np.sin(self.body[i].ex.phase) else: print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain any excitation coefficients' if 'sc_mag' in locals(): self.body[i].ex.sc.mag = sc_mag[6*i:6+6*i,:,:] self.body[i].ex.sc.phase = np.deg2rad(sc_phase[6*i:6+6*i,:,:]) self.body[i].ex.sc.re = sc_re[6*i:6+6*i,:,:] self.body[i].ex.sc.im = sc_im[6*i:6+6*i,:,:] else: pass # print 'Warning: body ' + str(i) + ' - The WAMTI .3sc file specified does not contain any scattering coefficients' if 'fk_mag' in locals(): self.body[i].ex.fk.mag = fk_mag[6*i:6+6*i,:,:] self.body[i].ex.fk.phase = np.deg2rad(fk_phase[6*i:6+6*i,:,:]) self.body[i].ex.fk.re = fk_re[6*i:6+6*i,:,:] self.body[i].ex.fk.im = fk_im[6*i:6+6*i,:,:] else: pass # print 'Warning: body ' + str(i) + ' - The WAMTI .3fk file specified does not contain any froude krylof coefficients' if 'rao_all' in locals(): self.body[i].rao.mag = rao_all[6*i:6+6*i,:,:] self.body[i].rao.phase = np.deg2rad(phase_all[6*i:6+6*i,:,:]) self.body[i].rao.re = self.body[i].rao.mag*np.cos(self.body[i].rao.phase) self.body[i].rao.im = self.body[i].rao.mag*np.sin(self.body[i].rao.phase) else: print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain any rao data' if 'ssy_all' in locals(): self.body[i].ssy.mag = ssy_all[6*i:6+6*i,:,:] self.body[i].ssy.phase = np.deg2rad(phase_all[6*i:6+6*i,:,:]) self.body[i].ssy.re = self.body[i].ssy.mag*np.cos(self.body[i].ssy.phase) self.body[i].ssy.im = self.body[i].ssy.mag*np.sin(self.body[i].ssy.phase) else: print 'Warning: body ' + str(i) + ' - The WAMTI .out file specified does not contain any rao data' self.body[i].bem_raw_data = raw self.body[i].bem_code = code self.body[i].scale(scale=self.scaled_at_read)
[docs]def read(out_file, density=1000., gravity=9.81, scale=False): ''' Function to read WAMIT data into a data object of type(WamitOutput) Parameters: out_file : str Name of the wamit .out output file. In order to read scattering and Froud-Krylof forces the .3sc (scatterin) and .3fk (Froud-Krylof) coefficinet files must have the same base name as the .out file. density : float, optional Water density used to scale the hydrodynamic coefficient data gravity : float, optional Acceleration due to gravity used to scale the hydrodynamic coefficient data scale : bool, optional Boolean value to determine if the hydrodynamic data is scaled. See the bemio.data_structures.bem.scale function for more information Returns: wamit_data A WamitData object that contains the data from the WAMIT .out file specified Examples: The following example assumes there is a WAMIT output file named `wamit.out` >>> wamit_data = read(out_file=wamit.out) ''' wamit_data = WamitOutput(out_file, density, gravity, scale) return wamit_data