def compute_spectrum( self, filename_phys, params, ): # # Get meta information about job # self.job_metadata_available = False try: # Step 1) Determine job directory name jobdir = os.path.dirname(filename_phys) print("Loading data from job directory '" + jobdir + "'") # Step 2) Load job meta information j = JobData(jobdir=jobdir) self.job_metadata_available = True except Exception as e: print(str(e)) self.job_metadata_available = False if self.job_metadata_available: data = j.get_flattened_data() if 'runtime.plane_domain_size' not in data: raise Exception( "Physical domain size must be specified via runtime parameters in MULE" ) domain_size = data['runtime.plane_domain_size'] if isinstance(domain_size, list): domain_size = domain_size[0] # # The following code is converted from a development of Pedro Peixoto to fit into the MULE framework # # some parameter mmin = 0 # Load file udata_ = PlaneDataPhysical(filename_phys) udata = udata_.data #Calculate spectrum #----------------------------------- print("Physical shape") print(udata.shape) uspec = np.fft.fft2(udata) / (udata.shape[0] * udata.shape[1]) print("Spectral shape") print(uspec.shape) # Calculate amplitude spectrum data = np.multiply(uspec, np.conjugate(uspec)) data = data.real n = data.shape[0] # Since data u,v data is real, the spectrum has a symmetry and all that matters is the 1st quadrant # we multiply by 2 to account for the symmetry data = 2 * data[0:int(n / 2) - 1, 0:int(n / 2) - 1] # Adjust data size n = data.shape[0] # m=int(n/2)+1 m = int(2 * n / 3) + 1 #anti-aliasing cut if mmin == 0: mmin = m else: if m > mmin: m = mmin print("Anti-aliased spectrum region:", m) #Calculate energy per shell # TODO: convert to linspace r = np.arange(0, m + 1, 1) # radius energy = np.zeros(m + 1) shell_pattern = np.zeros((m + 1, m + 1)) print("Generating energy in shells (Each . is 1/", m, ")") for i in range(0, m): for j in range(0, m): k = np.sqrt(pow(float(i), 2) + pow(float(j), 2)) intk = int(k) if intk < m: energy[intk] = energy[intk] + data[i, j] shell_pattern[i, j] = intk print(".", end='', flush=True) #print(i, j, k, intk, data[i,j], energy[intk], data.shape, energy.shape) print(".") #Quick check to see if things match #print("Energy in shells: ", energy[0:10]) #print("Energy in first column of data: ", data[0:10,0]) #print("Shell modes: ", r[0:10]) #print("Pattern:\n", shell_pattern[0:10,0:10]) self.spectrum = energy[:] self.spectrum_mode = r[:] if self.job_metadata_available: # Convert wavenumber to wavelength self.spectrum_wavelength = np.zeros(m + 1) self.spectrum_wavelength[1:] = domain_size * 1000 / r[1:] else: self.spectrum_wavelength = None
def compute_diff( self, filename_a, filename_b, params, ): # Load first file_b, to avoid wasting time for filename_a if filename_b doesn't exist file_b = PlaneDataPhysical(filename_b) file_a = PlaneDataPhysical(filename_a) self.norm_l1_value = 0.0 self.norm_l2_value = 0.0 self.norm_linf_value = 0.0 self.norm_rms_value = 0.0 self.N = 0 size_ref_j = len(file_a.data) size_ref_i = len(file_a.data[0]) size_cmp_j = len(file_b.data) size_cmp_i = len(file_b.data[0]) if size_ref_j == size_cmp_j and size_ref_i == size_cmp_i: # and False: self.info("Using 'default' method (matching resolutions)") data_ref = file_a.data data_cmp = file_b.data elif 'reduce_ref_to_cmp' in params: self.info("Using 'ref_reduce' method") # # Reduce reference solution, assuming that the # resolution is integer multiples of the one to compare with # data_ref = file_a.data data_cmp = file_b.data multiplier_j = size_ref_j / size_cmp_j multiplier_i = size_ref_i / size_cmp_i print("Dimensions of reference solution: ", size_ref_i, size_ref_j) print("Dimensions of method under analysis: ", size_cmp_i, size_cmp_j) if not float(multiplier_i).is_integer() or not float( multiplier_j).is_integer(): print("Grids are not aligned") print("Try to use (TODO) interpolation script") print("Dimensions of method under analysis: ", size_cmp_i, size_cmp_j) print("Multipliers: ", multiplier_i, multiplier_j) raise Exception("Grids not properly aligned") multiplier_j = int(multiplier_j) multiplier_i = int(multiplier_i) print("Using multipliers (int): ", multiplier_i, multiplier_j) data_ref_new = np.zeros(shape=data_cmp.shape) for j in range(0, size_cmp_j): for i in range(0, size_cmp_i): data_ref_new[j, i] = 0.0 for sj in range(0, multiplier_j): for si in range(0, multiplier_i): data_ref_new[j, i] += data_ref[j * multiplier_j + sj, i * multiplier_i + si] data_ref_new[j, i] /= multiplier_i * multiplier_j data_ref = data_ref_new elif ('interpolate' in params and size_ref_j > size_cmp_j and size_ref_i > size_cmp_i) or ('interpolate_cmp_to_ref' in params): self.info("Using 'interpolate_cmp_to_ref' method") # # Interpolate solution to resolution of reference solution. # Note, that this can also lead to a reduction in case of a lower resolution of the reference # # This is the code written by Pedro which uses spline interpolation # Comparison via interpolation # print("Interpolation") # A-grid REFERENCE (file1) - sweet outputs only A grids physical space data_ref = file_a.data data_cmp = file_b.data ny_ref = len(file_a.data) nx_ref = len(file_a.data[0]) print("REF resolution: " + str(nx_ref) + ", " + str(ny_ref)) ny_cmp = len(file_b.data) nx_cmp = len(file_b.data[0]) print("CMP resolution: " + str(nx_cmp) + ", " + str(ny_cmp)) dx_ref = 1.0 / (nx_ref) dy_ref = 1.0 / (ny_ref) x_ref = np.linspace(0, 1, nx_ref, endpoint=False) y_ref = np.linspace(0, 1, ny_ref, endpoint=False) x_ref += dx_ref / 2 # Make it cell-centered y_ref += dy_ref / 2 X_ref, Y_ref = np.meshgrid(x_ref, y_ref) # A-grid cmp file (file2) dx_cmp = 1.0 / nx_cmp dy_cmp = 1.0 / ny_cmp x_cmp = np.linspace(0, 1, nx_cmp, endpoint=False) y_cmp = np.linspace(0, 1, ny_cmp, endpoint=False) x_cmp += dx_cmp / 2 y_cmp += dy_cmp / 2 X_cmp, Y_cmp = np.meshgrid(x_cmp, y_cmp) # Create cubic interpolation of comparison # Data to be interpolated interp_spline = RectBivariateSpline(x_cmp, y_cmp, data_cmp) # Compute reduced reference resolution # Target grid data_cmp_high = interp_spline(x_ref, y_ref) data_cmp = data_cmp_high data_ref = data_ref elif ('interpolate' in params and size_ref_j < size_cmp_j and size_ref_i < size_cmp_i) or ('interpolate_ref_to_cmp' in params): self.info("Using 'interpolate_ref_to_cmp' method") # # Interpolate: REF => resolution(CMP) # # # Interpolate solution to resolution of reference solution. # Note, that this can also lead to a reduction in case of a lower resolution of the reference # # This is the code written by Pedro which uses spline interpolation # Comparison via interpolation # print("Interpolation") # A-grid REFERENCE (file1) - sweet outputs only A grids physical space data_ref = file_a.data data_cmp = file_b.data ny_ref = len(file_a.data) nx_ref = len(file_a.data[0]) print("REF resolution: " + str(nx_ref) + ", " + str(ny_ref)) ny_cmp = len(file_b.data) nx_cmp = len(file_b.data[0]) print("CMP resolution: " + str(nx_cmp) + ", " + str(ny_cmp)) dx_ref = 1.0 / nx_ref dy_ref = 1.0 / ny_ref x_ref = np.linspace(0, 1, nx_ref, endpoint=False) y_ref = np.linspace(0, 1, ny_ref, endpoint=False) x_ref += dx_ref / 2 # Make it cell-centered, this significantly reduces the errors y_ref += dy_ref / 2 X_ref, Y_ref = np.meshgrid(x_ref, y_ref) # A-grid cmp file (file2) dx_cmp = 1.0 / nx_cmp dy_cmp = 1.0 / ny_cmp x_cmp = np.linspace(0, 1, nx_cmp, endpoint=False) y_cmp = np.linspace(0, 1, ny_cmp, endpoint=False) x_cmp += dx_cmp / 2 y_cmp += dy_cmp / 2 X_cmp, Y_cmp = np.meshgrid(x_cmp, y_cmp) # Create cubic interpolation of reference file interp_spline = RectBivariateSpline(x_ref, y_ref, data_ref) # Compute reduced reference resolution data_ref_low = interp_spline(x_cmp, y_cmp) data_ref = data_ref_low #elif 'spectral_ref_to_cmp' in params: elif 'spectral_ref_to_cmp' in params or 'spectral' in params: self.info("Using 'spectral_ref_to_cmp' method") # This is the code written by Pedro which uses spline interpolation # Comparison via interpolation # print("Interpolation") # A-grid REFERENCE (file1) - sweet outputs only A grids physical space data_ref = file_a.data data_cmp = file_b.data """ #if True: if False: data_ref = np.zeros((8, 8)) data_cmp = np.zeros((6, 6)) for i in range(len(data_ref[0])): for j in range(len(data_ref)): data_ref[j,i] = 1.0 a = 1.0 a *= math.sin(2.0*i*math.pi*2.0/len(data_ref[0])) a *= math.cos(2.0*j*math.pi*2.0/len(data_ref)) data_ref[j,i] += a a = 1.0 a *= math.sin(i*math.pi*2.0/len(data_ref[0])) a *= math.cos(j*math.pi*2.0/len(data_ref)) data_ref[j,i] += a for i in range(len(data_cmp[0])): for j in range(len(data_cmp)): data_cmp[j,i] = 1.0 a = 1.0 a *= math.sin(2.0*i*math.pi*2.0/len(data_cmp[0])) a *= math.cos(2.0*j*math.pi*2.0/len(data_cmp)) data_cmp[j,i] += a a = 1.0 a *= math.sin(i*math.pi*2.0/len(data_cmp[0])) a *= math.cos(j*math.pi*2.0/len(data_cmp)) data_cmp[j,i] += a """ ny_ref = len(data_ref) nx_ref = len(data_ref[0]) res_ref = nx_ref * ny_ref print("REF resolution: " + str(nx_ref) + ", " + str(ny_ref)) ny_cmp = len(data_cmp) nx_cmp = len(data_cmp[0]) res_cmp = nx_cmp * ny_cmp print("CMP resolution: " + str(nx_cmp) + ", " + str(ny_cmp)) if nx_cmp & 1 or ny_cmp & 1: raise Exception("Only even resolutions allowed") # # Spectral rescaling # shift_ref_i = -1.0 / size_ref_i * 0.5 shift_ref_j = -1.0 / size_ref_j * 0.5 shift_cmp_j = 1.0 / size_cmp_j * 0.5 shift_cmp_i = 1.0 / size_cmp_i * 0.5 #if False: if True: # # RFFT # # Convert reference data to spectrum data_ref_spec = np.fft.rfft2(data_ref) # Dummy transformation to get matching spectral size data_ref_new_spec = np.fft.rfft2( np.zeros(shape=data_cmp.shape)) specx = data_ref_spec.shape[1] specy = data_ref_spec.shape[0] newspecx = data_ref_new_spec.shape[1] newspecy = data_ref_new_spec.shape[0] data_ref_new_spec[0:newspecy // 2, 0:newspecx] = data_ref_spec[0:newspecy // 2, 0:newspecx] d = specy - newspecy // 2 nd = newspecy - newspecy // 2 data_ref_new_spec[nd:nd + newspecy // 2, 0:newspecx] = data_ref_spec[d:d + newspecy // 2, 0:newspecx] """ print("*"*80) print(data_ref_spec) print("*"*80) print(data_ref_new_spec) print("*"*80) """ def shift( spec_data, # spectral data sh_x, # shift in x direction within domain [0;1] sh_y, # shift in y direction within domain [0;1] ): # return data ret_data = np.zeros(spec_data.shape, dtype=complex) for iy in range(spec_data.shape[0]): # compute mode if iy < spec_data.shape[0] // 2: ky = iy else: ky = iy - spec_data.shape[0] for ix in range(spec_data.shape[1]): # compute mode kx = ix ret_data[iy, ix] = spec_data[iy, ix] #ret_data[iy,ix] *= np.exp(1j*2.0*math.pi*kx*sh_x) #ret_data[iy,ix] *= np.exp(1j*2.0*math.pi*ky*sh_y) ret_data[iy, ix] *= np.exp(1j * 2.0 * math.pi * (kx * sh_x + ky * sh_y)) return ret_data # Shift high res reference data to 0,0 data_ref_new_spec = shift(data_ref_new_spec, shift_ref_i + shift_cmp_i, shift_ref_j + shift_cmp_j) data_ref_new = np.fft.irfft2(data_ref_new_spec) data_ref_new *= res_cmp / res_ref else: # # FFT # # Convert reference data to spectrum data_ref_spec = np.fft.fft2(data_ref) # Dummy transformation to get matching spectral size data_ref_new_spec = np.fft.fft2(np.zeros(shape=data_cmp.shape)) specx = data_ref_spec.shape[1] specy = data_ref_spec.shape[0] newspecx = data_ref_new_spec.shape[1] newspecy = data_ref_new_spec.shape[0] dy = specy - newspecy // 2 ndy = newspecy - newspecy // 2 dx = specx - newspecx // 2 ndx = newspecx - newspecx // 2 data_ref_new_spec[0:newspecy // 2, 0:newspecx // 2] = data_ref_spec[0:newspecy // 2, 0:newspecx // 2] data_ref_new_spec[ndy:ndy + newspecy // 2, 0:newspecx // 2] = data_ref_spec[dy:dy + newspecy // 2, 0:newspecx // 2] data_ref_new_spec[0:newspecy // 2, ndx:ndx + newspecx // 2] = data_ref_spec[0:newspecy // 2, dx:dx + newspecx // 2] data_ref_new_spec[ndy:ndy + newspecy // 2, ndx:ndx + newspecx // 2] = data_ref_spec[dy:dy + newspecy // 2, dx:dx + newspecx // 2] if False: print("*" * 80) print(data_ref_spec) print("*" * 80) print(data_ref_new_spec) print("*" * 80) def shift( spec_data, # spectral data sh_x, # shift in x direction within domain [0;1] sh_y, # shift in y direction within domain [0;1] ): # return data ret_data = np.zeros(spec_data.shape, dtype=complex) for iy in range(spec_data.shape[0]): # compute mode if iy < spec_data.shape[0] // 2: ky = iy else: ky = iy - spec_data.shape[0] for ix in range(spec_data.shape[1]): # compute mode if ix < spec_data.shape[1] // 2: kx = ix else: kx = ix - spec_data.shape[1] ret_data[iy, ix] = spec_data[iy, ix] ret_data[iy, ix] *= np.exp(1j * 2.0 * math.pi * kx * sh_x) ret_data[iy, ix] *= np.exp(1j * 2.0 * math.pi * ky * sh_y) return ret_data # Shift high res reference data to 0,0 data_ref_new_spec = shift(data_ref_new_spec, shift_ref_i + shift_cmp_i, shift_ref_j + shift_cmp_j) data_ref_new = np.fft.ifft2(data_ref_new_spec) data_ref_new *= res_cmp / res_ref # Restrict to real data data_ref_new = np.real(data_ref_new) # The axes might be wrong. # # Swap axis=1 and axis=0 if there are some errors. # #f = signal.resample(data_ref, nx_cmp, t=None, axis=0) #data_ref_new = signal.resample(f, ny_cmp, t=None, axis=1) data_ref = data_ref_new else: print("") print("No supported method provided in '" + (','.join(params)) + "'") print("") raise Exception("No supported method provided in '" + (','.join(params)) + "'") # # Grids have same resolution # for j in range(0, data_cmp.shape[0]): for i in range(0, data_cmp.shape[1]): value = data_cmp[j, i] - data_ref[j, i] # http://mathworld.wolfram.com/L1-Norm.html self.norm_l1_value += abs(value) # http://mathworld.wolfram.com/L2-Norm.html self.norm_l2_value += value * value # http://mathworld.wolfram.com/L-Infinity-Norm.html self.norm_linf_value = max(abs(value), self.norm_linf_value) # http://mathworld.wolfram.com/Root-Mean-Square.html self.norm_rms_value += value * value self.N += 1 # Compute sqrt() for Euklidian L2 norm self.norm_l2_value = math.sqrt(self.norm_l2_value) # RMS final sqrt(N) computation self.norm_rms_value = math.sqrt(self.norm_rms_value / float(self.N)) # resolution normalized L1 value self.res_norm_l1_value = self.norm_l1_value / float(self.N)