From 1703291117f7b1054ad2aba215b725a6721ac60b Mon Sep 17 00:00:00 2001 From: dreamer2368 Date: Fri, 23 Dec 2022 16:45:56 -0600 Subject: [PATCH] converted all example config.py files. --- .github/workflows/optim_grad_test.sh | 2 +- .github/workflows/optim_test.sh | 2 +- examples/AcousticMonopole/config.py | 8 +- examples/AcousticMonopole/config.py2 | 90 +++ examples/BoundaryLayer/config.py | 2 +- examples/BoundaryLayer/config.py2 | 95 +++ examples/ChannelFlow/config.py | 6 +- examples/ChannelFlow/config.py2 | 75 ++ examples/Cylinder/config.py | 8 +- examples/Cylinder/config.py2 | 87 +++ examples/DeformingWall2D/config.py | 12 +- examples/DeformingWall2D/config.py2 | 206 ++++++ examples/FiveBlockMesh/config.py | 8 +- examples/FiveBlockMesh/config.py2 | 129 ++++ examples/KolmogorovFlow/config.py | 8 +- examples/KolmogorovFlow/config.py2 | 94 +++ examples/MultiblockAcousticMonopole/config.py | 8 +- .../MultiblockAcousticMonopole/config.py2 | 101 +++ examples/MultiblockJet/config.py | 22 +- examples/MultiblockJet/config.py2 | 698 ++++++++++++++++++ examples/MultiblockJetCoflow/config.py | 14 +- examples/MultiblockJetCoflow/config.py2 | 596 +++++++++++++++ examples/MultiblockOneDWave/config.py | 8 +- examples/MultiblockOneDWave/config.py2 | 125 ++++ examples/NACA0012/config.py | 120 +-- examples/NACA0012/config.py2 | 125 ++++ examples/OSUMach1.3/config.py | 214 +++--- examples/OSUMach1.3/config.py2 | 584 +++++++++++++++ examples/OneDWave/config.py | 8 +- examples/OneDWave/config.py2 | 118 +++ examples/TDML/config.py | 98 +++ examples/TestForcing/config.py | 8 +- examples/TestForcing/config.py2 | 53 ++ examples/VortexDynamics/config.py | 12 +- examples/VortexDynamics/config.py2 | 226 ++++++ examples/WeiFreundSDML/config.py | 8 +- examples/WeiFreundSDML/config.py2 | 99 +++ 37 files changed, 3838 insertions(+), 239 deletions(-) create mode 100644 examples/AcousticMonopole/config.py2 create mode 100644 examples/BoundaryLayer/config.py2 create mode 100644 examples/ChannelFlow/config.py2 create mode 100644 examples/Cylinder/config.py2 create mode 100644 examples/DeformingWall2D/config.py2 create mode 100644 examples/FiveBlockMesh/config.py2 create mode 100644 examples/KolmogorovFlow/config.py2 create mode 100644 examples/MultiblockAcousticMonopole/config.py2 create mode 100644 examples/MultiblockJet/config.py2 create mode 100644 examples/MultiblockJetCoflow/config.py2 create mode 100644 examples/MultiblockOneDWave/config.py2 create mode 100644 examples/NACA0012/config.py2 create mode 100644 examples/OSUMach1.3/config.py2 create mode 100644 examples/OneDWave/config.py2 create mode 100644 examples/TDML/config.py create mode 100644 examples/TestForcing/config.py2 create mode 100644 examples/VortexDynamics/config.py2 create mode 100644 examples/WeiFreundSDML/config.py2 diff --git a/.github/workflows/optim_grad_test.sh b/.github/workflows/optim_grad_test.sh index 0f04dfb0..01d15b7e 100644 --- a/.github/workflows/optim_grad_test.sh +++ b/.github/workflows/optim_grad_test.sh @@ -23,7 +23,7 @@ if [ $? -ne 0 ]; then exit -1; fi echo "Generating grid and solutions for ${EXAMPLE}" cd ${EXAMPLE} -python2 config.py +python3 config.py if [ $? -ne 0 ]; then exit -1; fi echo "Generating links to executables in ${EXAMPLE}" diff --git a/.github/workflows/optim_test.sh b/.github/workflows/optim_test.sh index da72104a..58d9a94d 100644 --- a/.github/workflows/optim_test.sh +++ b/.github/workflows/optim_test.sh @@ -24,7 +24,7 @@ if [ $? -ne 0 ]; then exit -1; fi echo "Generating grid and solutions for ${EXAMPLE}" cd ${EXAMPLE} -python2 config.py +python3 config.py if [ $? -ne 0 ]; then exit -1; fi echo "Generating links to executables in ${EXAMPLE}" diff --git a/examples/AcousticMonopole/config.py b/examples/AcousticMonopole/config.py index 3b6eafd0..af8ed58e 100644 --- a/examples/AcousticMonopole/config.py +++ b/examples/AcousticMonopole/config.py @@ -29,8 +29,8 @@ def target_mollifier(g): g.xyz[0][:,j,0,0], x_min, x_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -49,8 +49,8 @@ def control_mollifier(g): g.xyz[0][i,:,0,1], y_min, y_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/AcousticMonopole/config.py2 b/examples/AcousticMonopole/config.py2 new file mode 100644 index 00000000..3b6eafd0 --- /dev/null +++ b/examples/AcousticMonopole/config.py2 @@ -0,0 +1,90 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def grid(size): + x_min = -14. + x_max = 14. + y_min = -14. + y_max = 14. + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0]) + y = np.linspace(y_min, y_max, g.size[0,1]) + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def target_mollifier(g): + x_min = -1. + x_max = 1. + y_min = -10. + y_max = 10. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.tanh_support( + g.xyz[0][i,:,0,1], y_min, y_max, 40., 0.2) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 5. + y_min = -2. + y_max = 2. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][i,:,0,1], y_min, y_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + f.f[0][:,:,:,0] = s.toprimitive().q[0][:,:,:,4] + return f + +def random_solution(g,time=0.0,timestep=0): + + gamma = 1.4 + s = p3d.Solution().copy_from(g).quiescent(gamma) + n = s.get_size(0) + s.q[0][:,:,0,0] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 1.0 + s.q[0][:,:,0,1] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-3 + 0.0 + s.q[0][:,:,0,2] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-3 + 0.0 + s.q[0][:,:,0,4] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 1./(gamma-1.) + s.q[0][:,:,0,4] *= (gamma-1.)/gamma * s.q[0][:,:,0,0] + + s.time = time + s._format.aux_header[0] = timestep + + return s.fromprimitive(gamma) + +if __name__ == '__main__': + g = grid([201, 201]) + g.save('AcousticMonopole.xyz') + gamma = 1.4 + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.save('AcousticMonopole.ic.q') + mean_pressure(s).save('AcousticMonopole.mean_pressure.f') + + # dt = 5.0e-2 + # Nt = 100 + # for k in range(2): + # random_solution(g,k*Nt*dt,k*Nt).save('AcousticMonopole-%d.ic.q'%k) + target_mollifier(g).save('AcousticMonopole.target_mollifier.f') + control_mollifier(g).save('AcousticMonopole.control_mollifier.f') diff --git a/examples/BoundaryLayer/config.py b/examples/BoundaryLayer/config.py index a3db1121..37cc2e43 100644 --- a/examples/BoundaryLayer/config.py +++ b/examples/BoundaryLayer/config.py @@ -30,7 +30,7 @@ def grid(size, mapping_type='sinh'): sigma = fsolve(lambda x: (y_max - y_min) / dy_min - num_uniform + 1 - (x ** (g.size[0,1] - num_uniform) - 1.) / (x - 1.), 1.02) - print 100. * (sigma - 1.) + print(100. * (sigma - 1.)) y = np.append([0.], np.cumsum( [dy_min if r < num_uniform - 1 else dy_min * sigma ** (r - num_uniform + 1) diff --git a/examples/BoundaryLayer/config.py2 b/examples/BoundaryLayer/config.py2 new file mode 100644 index 00000000..a3db1121 --- /dev/null +++ b/examples/BoundaryLayer/config.py2 @@ -0,0 +1,95 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def mapping_function(x, sigma): + return np.sinh(sigma * x) / np.sinh(sigma) + +def grid(size, mapping_type='sinh'): + from scipy.optimize import fsolve + x_min = -150. + x_max = 150. + y_min = 0. + y_max = 50. + z_min = -40. + z_max = 40. + dy_min = 0.016 + num_uniform = 7 + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0] + 1)[:-1] + if mapping_type == 'sinh': + sigma = fsolve(lambda x: ( + (y_max - y_min - num_uniform * dy_min) * mapping_function( + 1. / (g.size[0,1] - 1.), x) - dy_min) ** 2, 2.) + y = np.append(np.linspace(y_min, y_min + dy_min * num_uniform, + num_uniform + 1), y_min + dy_min * + num_uniform + (y_max - y_min - num_uniform * dy_min) * + mapping_function(np.linspace(0., 1., g.size[0,1] - + num_uniform), sigma)[1:]) + else: + sigma = fsolve(lambda x: (y_max - y_min) / dy_min - num_uniform + 1 - + (x ** (g.size[0,1] - num_uniform) - 1.) / + (x - 1.), 1.02) + print 100. * (sigma - 1.) + y = np.append([0.], np.cumsum( + [dy_min if r < num_uniform - 1 + else dy_min * sigma ** (r - num_uniform + 1) + for r in range(g.size[0,1] - 1)])) + z = np.linspace(z_min, z_max, g.size[0,2] + 1)[:-1] + for i in range(x.size): + g.xyz[0][i,:,:,0] = x[i] + for j in range(y.size): + g.xyz[0][:,j,:,1] = y[j] + for k in range(z.size): + g.xyz[0][:,:,k,2] = z[k] + return g + +def target_state(g, mach_number=0.5, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,1] = mach_number + return s.fromprimitive() + +def initial_condition(g, external_grid='External/RocFlo-CM.00000000.xyz', + external_solution='External/RocFlo-CM.00240000.q', + chunk_size=20): + from scipy.signal import resample + from scipy.interpolate import interp1d + x, y, z = g.xyz[0][:,0,0,0], g.xyz[0][0,:,0,1], g.xyz[0][0,0,:,2] + ge = p3d.Grid(external_grid) + xe = ge.set_subzone(0, [0, 0, 0], [-2, 0, 0]).load().xyz[0][:,0,0,0] + ye = ge.set_subzone(0, [0, 0, 0], [0, -1, 0]).load().xyz[0][0,:,0,1] + ze = ge.set_subzone(0, [0, 0, 0], [0, 0, -2]).load().xyz[0][0,0,:,2] + if x.size == xe.size and z.size == ze.size: + st = p3d.fromfile(external_solution, 0, [0, 0, 0], [-2, -1, -2]) + else: + st = p3d.Solution().set_size([x.size, ye.size, z.size], True) + ends = [int(d) for d in np.linspace(chunk_size - 1, ye.size - 1, + ye.size / chunk_size)] + subzones = [([0, ends[i-1] + 1, 0], [-2, ends[i], -2]) + if i > 0 else ([0, 0, 0], [-2, ends[0], -2]) + for i in range(len(ends))] + se = p3d.Solution(external_solution) + for subzone in subzones: + se.set_subzone(0, *subzone).load() + q = np.empty_like(se.q[0], dtype='float64') + q[:,:,:,:] = se.q[0] + if x.size != xe.size: + q = resample(q, x.size, axis=0, window='hann') + if z.size != ze.size: + q = resample(q, z.size, axis=2, window='hann') + st.q[0][:,subzone[0][1]:subzone[1][1]+1,:,:] = q + s = p3d.Solution().copy_from(g) + for j in range(5): + for k in range(z.size): + for i in range(x.size): + f = interp1d(ye, st.q[0][i,:,k,j], kind='linear', + bounds_error=False, fill_value=st.q[0][i,-1,k,j]) + s.q[0][i,0,k,j] = st.q[0][i,0,k,j] + s.q[0][i,1:,k,j] = f(y[1:]) + return s + +if __name__ == '__main__': + g = grid([500, 216, 400], mapping_type='geom') + g.save('BoundaryLayer.xyz') + target_state(g).save('BoundaryLayer.target.q') + initial_condition(g).save('BoundaryLayer.ic.q') diff --git a/examples/ChannelFlow/config.py b/examples/ChannelFlow/config.py index d0024b36..b0691c48 100644 --- a/examples/ChannelFlow/config.py +++ b/examples/ChannelFlow/config.py @@ -25,7 +25,7 @@ def grid(size, eta=0.97): dx, dz = (x_max-x_min)/g.size[0,0], (z_max-z_min)/g.size[0,2] dy = y[1:] - y[:-1] - print ('dx : %.5E, dz : %.5E, dy_min : %.5E, dy_max : %.5E' % (dx,dz,np.min(dy),np.max(dy)) ) + print(('dx : %.5E, dz : %.5E, dy_min : %.5E, dy_max : %.5E' % (dx,dz,np.min(dy),np.max(dy)) )) for i in range(x.size): g.xyz[0][i,:,:,0] = x[i] @@ -55,8 +55,8 @@ def initial_condition(g, mach_number=1.5, gamma=1.4): amp = amp[0] + amp[1] * 1.0j phase = 2.0 * np.pi * np.random.rand(2) yphase = 2 * np.random.randint(2) - 1 - print ('amp: (%.15E + %.15E i), phase: (%.15E, %.15E), y-phase: %d' - %(amp.real,amp.imag,phase[0],phase[1],yphase)) + print(('amp: (%.15E + %.15E i), phase: (%.15E, %.15E), y-phase: %d' + %(amp.real,amp.imag,phase[0],phase[1],yphase))) temp[:,1:-1,:,dim] += u0[:,1:-1,:] * amp \ * np.sin( k * np.pi * y[:,1:-1,:] * yphase ) \ * np.exp( l * 0.5j * x[:,1:-1,:] + phase[0] * 1.0j ) \ diff --git a/examples/ChannelFlow/config.py2 b/examples/ChannelFlow/config.py2 new file mode 100644 index 00000000..d0024b36 --- /dev/null +++ b/examples/ChannelFlow/config.py2 @@ -0,0 +1,75 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def mapping_function(x, sigma): + return np.sinh(sigma * x) / np.sinh(sigma) + +def grid(size, eta=0.97): + from scipy.optimize import fsolve + x_min = -2.0 * np.pi + x_max = 2.0 * np.pi + y_min = -1.0 + y_max = 1.0 + z_min = -2.0 / 3.0 * np.pi + z_max = 2.0 / 3.0 * np.pi + dy_min = 0.016 + num_uniform = 7 + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0] + 1)[:-1] + z = np.linspace(z_min, z_max, g.size[0,2] + 1)[:-1] + + xi = np.linspace(-1.0, 1.0, g.size[0,1]) + y = np.sin(eta*xi*np.pi/2.0) / np.sin(eta*np.pi/2.0) + y *= (y_max - y_min)/2.0 + + dx, dz = (x_max-x_min)/g.size[0,0], (z_max-z_min)/g.size[0,2] + dy = y[1:] - y[:-1] + print ('dx : %.5E, dz : %.5E, dy_min : %.5E, dy_max : %.5E' % (dx,dz,np.min(dy),np.max(dy)) ) + + for i in range(x.size): + g.xyz[0][i,:,:,0] = x[i] + for j in range(y.size): + g.xyz[0][:,j,:,1] = y[j] + for k in range(z.size): + g.xyz[0][:,:,k,2] = z[k] + return g + +def initial_condition(g, mach_number=1.5, gamma=1.4): + x = g.xyz[0][:,:,:,0] + y = g.xyz[0][:,:,:,1] + z = g.xyz[0][:,:,:,2] + u0 = mach_number * 1.5 * ( 1.0 - y**2 ) + + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,0] = 1.0 + s.q[0][:,:,:,1:4] = 0.0 + s.q[0][:,:,:,4] = 1.0 / gamma + + temp = np.zeros_like(s.q[0][:,:,:,1:4],dtype=np.complex128) + for k in range(3,6): + for l in range(18,21): + for m in range(6,9): + for dim in range(3): + amp = np.random.rand(2) + amp = amp[0] + amp[1] * 1.0j + phase = 2.0 * np.pi * np.random.rand(2) + yphase = 2 * np.random.randint(2) - 1 + print ('amp: (%.15E + %.15E i), phase: (%.15E, %.15E), y-phase: %d' + %(amp.real,amp.imag,phase[0],phase[1],yphase)) + temp[:,1:-1,:,dim] += u0[:,1:-1,:] * amp \ + * np.sin( k * np.pi * y[:,1:-1,:] * yphase ) \ + * np.exp( l * 0.5j * x[:,1:-1,:] + phase[0] * 1.0j ) \ + * np.exp( m * 1.5j * z[:,1:-1,:] + phase[1] * 1.0j ) + + temp = temp.real + temp *= 0.05 * mach_number * 1.5 / np.amax(np.abs(temp)) + + s.q[0][:,:,:,1] = u0 + s.q[0][:,:,:,1:4] += temp.real + return s.fromprimitive() + +if __name__ == '__main__': + g = grid([300, 200, 300],eta=0.99) + g.save('ChannelFlow.xyz') + initial_condition(g).save('ChannelFlow.ic.q') diff --git a/examples/Cylinder/config.py b/examples/Cylinder/config.py index 32848dd7..0325e6b0 100644 --- a/examples/Cylinder/config.py +++ b/examples/Cylinder/config.py @@ -54,8 +54,8 @@ def target_mollifier(g): for j in range(n[1]): f.f[0][:,j,0,0] *= p3d.cubic_bspline_support(r, r_min, r_max) imin, imax = p3d.find_extents(r, r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, 1, -1, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, 1, -1, 1, -1)) return f def control_mollifier(g): @@ -69,8 +69,8 @@ def control_mollifier(g): f.f[0][:,:,0,0] *= p3d.tanh_support(r, r_min - (r_max - r_min), r_max, 20., 0.4, False) imin, imax = p3d.find_extents(r[:,0], r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, 1, -1, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, 1, -1, 1, -1)) return f def mean_pressure(s): diff --git a/examples/Cylinder/config.py2 b/examples/Cylinder/config.py2 new file mode 100644 index 00000000..32848dd7 --- /dev/null +++ b/examples/Cylinder/config.py2 @@ -0,0 +1,87 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def mapping_function(x, sigma): + return np.sinh(sigma * x) / np.sinh(sigma) + +def radial_coordinate(n, mapping_type='geom', r_buffer=800., dr_min=0.005): + from scipy.optimize import fsolve + r_min = 0.5 + r_max = r_buffer + num_uniform = 50 + if mapping_type == 'sinh': + sigma = fsolve(lambda x: ( + (r_max - r_min - num_uniform * dr_min) * mapping_function( + 1. / (n - 1.), x) - dr_min) ** 2, 2.) + r = np.append(np.linspace(r_min, r_min + dr_min * num_uniform, + num_uniform + 1), r_min + dr_min * + num_uniform + (r_max - r_min - num_uniform * dr_min) * + mapping_function(np.linspace( + 0., 1., n - num_uniform), sigma)[1:]) + else: + sigma = fsolve(lambda x: (r_max - r_min) / dr_min - num_uniform + 1 - + (x ** (n - num_uniform) - 1.) / + (x - 1.), 1.02) + r = r_min + np.append([0.], np.cumsum( + [dr_min if r < num_uniform - 1 + else dr_min * sigma ** (r - num_uniform + 1) + for r in range(n - 1)])) + return r + +def grid(grid_size): + r = radial_coordinate(grid_size[0], r_buffer=300.) + p3d.mesh_stats(r) + theta = np.linspace(-np.pi, np.pi, grid_size[1]) + g = p3d.Grid().set_size([r.size, theta.size, 1], True) + r, theta = np.meshgrid(r, theta) + g.xyz[0][:,:,0,0] = np.transpose(r * np.cos(theta)) + g.xyz[0][:,:,0,1] = np.transpose(r * np.sin(theta)) + return g + +def target_state(g, mach_number, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,1] = mach_number + return s.fromprimitive(gamma) + +def target_mollifier(g): + r_min = 30. + r_max = 40. + r = np.sqrt(g.xyz[0][:,0,0,0] ** 2 + g.xyz[0][:,0,0,1] ** 2) + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support(r, r_min, r_max) + imin, imax = p3d.find_extents(r, r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, 1, -1, 1, -1) + return f + +def control_mollifier(g): + r_min = 0.5 + r_max = 0.64 + r = np.sqrt(g.xyz[0][:,:,0,0] ** 2 + g.xyz[0][:,:,0,1] ** 2) + theta = np.arctan2(g.xyz[0][:,:,0,1], g.xyz[0][:,:,0,0]) + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + f.f[0][:,:,0,0] *= p3d.tanh_support(r, r_min - (r_max - r_min), + r_max, 20., 0.4, False) + imin, imax = p3d.find_extents(r[:,0], r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, 1, -1, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + f.f[0][:,:,:,0] = s.toprimitive().q[0][:,:,:,4] + return f + +if __name__ == '__main__': + g = grid([408, 501]) + g.save('Cylinder.xyz') + target_state(g, mach_number=0.2).save('Cylinder.target.q') + target_mollifier(g).save('Cylinder.target_mollifier.f') + control_mollifier(g).save('Cylinder.control_mollifier.f') + diff --git a/examples/DeformingWall2D/config.py b/examples/DeformingWall2D/config.py index 129aa960..3958b11d 100644 --- a/examples/DeformingWall2D/config.py +++ b/examples/DeformingWall2D/config.py @@ -33,7 +33,7 @@ def grid(size, Lx, dip_range, mapping_type='sinh'): sigma = fsolve(lambda x: (y_max - y_min) / dy_min - num_uniform + 1 - (x ** (size[1] - num_uniform) - 1.) / (x - 1.), 1.02) - print 100. * (sigma - 1.) + print(100. * (sigma - 1.)) y = np.append([0.], np.cumsum( [dy_min if r < num_uniform - 1 else dy_min * sigma ** (r - num_uniform + 1) @@ -65,8 +65,8 @@ def grid(size, Lx, dip_range, mapping_type='sinh'): patchRange = int(1.5 * depthIdx) formatStr = ' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}' - print(formatStr.format('immersed1', 'IMMERSED_BOUNDARY', - 1, 0, 1, -1, 1, patchRange, 1, -1)) + print((formatStr.format('immersed1', 'IMMERSED_BOUNDARY', + 1, 0, 1, -1, 1, patchRange, 1, -1))) # print(formatStr.format('interface.S1', 'SAT_BLOCK_INTERFACE', # 1, 2, leftIdx, rightIdx, 1, 1, 1, -1)) # print(formatStr.format('interface.N2', 'SAT_BLOCK_INTERFACE', @@ -113,7 +113,7 @@ def stateRhs(fv, dfv): fvHist[n] = np.copy(fv) res = fv[1] - 1.0 if (abs(res) < threshold): - print(iter, abs(res)) + print((iter, abs(res))) break else: fv0[-1] -= res / dfv[1] @@ -135,7 +135,7 @@ def initial_condition(g, mach_number=1.0 / 343.0, gamma=1.4, Re = 1.16e6): xmin = np.amin(x) delta = np.sqrt((x - xmin) / Re / mach_number + 1.0) eta = y / delta - print(eta[0, 10, -1], eta[-1, 10, -1]) + print((eta[0, 10, -1], eta[-1, 10, -1])) blasiusTable = solve_blasius(1.5 * np.amax(eta)) uTable = mach_number * blasiusTable[:, 2] vtTable = 0.5 * (blasiusTable[:, 0] * blasiusTable[:, 2] - blasiusTable[:, 1]) @@ -194,7 +194,7 @@ def initial_condition_from_exp(g, expFilename, Lx = 5.0, a0 = 343.0, gamma = 1.4 gamma = 1.4 nu0 = 1.48e-5 # m2/s Re = Lx * 1e-3 * a0 / nu0 - print("Reynolds number: %.5E" % Re) + print(("Reynolds number: %.5E" % Re)) expFile = 'UV.4.5v_0msC.txt' dip_range = np.array([0.0, 15.0, 7.5]) diff --git a/examples/DeformingWall2D/config.py2 b/examples/DeformingWall2D/config.py2 new file mode 100644 index 00000000..129aa960 --- /dev/null +++ b/examples/DeformingWall2D/config.py2 @@ -0,0 +1,206 @@ +#!/usr/bin/env python +import numpy as np +import scipy.sparse as sps +import plot3dnasa as p3d + +def mapping_function(x, sigma): + return np.sinh(sigma * x) / np.sinh(sigma) + +def grid(size, Lx, dip_range, mapping_type='sinh'): + dip_range /= Lx + + from scipy.optimize import fsolve + x_min = 0. / Lx + x_max = 180. / Lx + y_min = 0. / Lx + y_max = 30. / Lx + z_min = -40. / Lx + z_max = 40. / Lx + dy_min = 0.016 + num_uniform = 7 + + x = np.linspace(x_min, x_max, size[0] + 1)[:-1] + if mapping_type == 'sinh': + sigma = fsolve(lambda x: ( + (y_max - y_min - num_uniform * dy_min) * mapping_function( + 1. / (size[1] - 1.), x) - dy_min) ** 2, 2.) + y = np.append(np.linspace(y_min, y_min + dy_min * num_uniform, + num_uniform + 1), y_min + dy_min * + num_uniform + (y_max - y_min - num_uniform * dy_min) * + mapping_function(np.linspace(0., 1., size[1] - + num_uniform), sigma)[1:]) + else: + sigma = fsolve(lambda x: (y_max - y_min) / dy_min - num_uniform + 1 - + (x ** (size[1] - num_uniform) - 1.) / + (x - 1.), 1.02) + print 100. * (sigma - 1.) + y = np.append([0.], np.cumsum( + [dy_min if r < num_uniform - 1 + else dy_min * sigma ** (r - num_uniform + 1) + for r in range(size[1] - 1)])) + + # leftIdx, rightIdx = p3d.find_extents(x, dip_range[0], dip_range[1]) + dummy, depthIdx = p3d.find_extents(y, 0.0, dip_range[2]) + # assert(leftIdx >= 1) + # assert(rightIdx <= size[0]) + assert(depthIdx <= size[1]) + size[1] += depthIdx - 1 + y = np.append(-y[(depthIdx-1):0:-1], y) + + # sizes = [size, [rightIdx - leftIdx + 1, depthIdx]] + # print(sizes) + g = p3d.Grid().set_size(size, True) + # z = np.linspace(z_min, z_max, g.size[0,2] + 1)[:-1] + for i in range(x.size): + g.xyz[0][i,:,:,0] = x[i] + for j in range(y.size): + g.xyz[0][:,j,:,1] = y[j] + # for k in range(z.size): + # g.xyz[0][:,:,k,2] = z[k] + + # for i in range(rightIdx - leftIdx + 1): + # g.xyz[1][i,:,:,0] = x[i + leftIdx - 1] + # for j in range(depthIdx): + # g.xyz[1][:,-1-j,:,1] = -y[j] + + patchRange = int(1.5 * depthIdx) + formatStr = ' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}' + print(formatStr.format('immersed1', 'IMMERSED_BOUNDARY', + 1, 0, 1, -1, 1, patchRange, 1, -1)) + # print(formatStr.format('interface.S1', 'SAT_BLOCK_INTERFACE', + # 1, 2, leftIdx, rightIdx, 1, 1, 1, -1)) + # print(formatStr.format('interface.N2', 'SAT_BLOCK_INTERFACE', + # 2, -2, 1, -1, -1, -1, 1, -1)) + # print(formatStr.format('immersed1', 'IMMERSED_BOUNDARY', + # 1, 0, leftIdx, rightIdx, 1, depthIdx, 1, -1)) + # print(formatStr.format('immersed2', 'IMMERSED_BOUNDARY', + # 2, 0, 1, -1, 1, -1, 1, -1)) + # print(formatStr.format('flatPlate.S1', 'SAT_ISOTHERMAL_WALL', + # 1, 2, 1, leftIdx - 1, 1, 1, 1, -1)) + # print(formatStr.format('flatPlate.N1', 'SAT_ISOTHERMAL_WALL', + # 1, 2, rightIdx + 1, -1, 1, 1, 1, -1)) + return g + +def solve_blasius(eta_max, Ng = 1001): + eta = np.linspace(0., eta_max, Ng) + dx = eta_max / Ng + f = np.zeros(Ng,) + + # Shooting method + fv0 = np.zeros(3,) + dfv0 = np.array([0., 0., 1.]) + fvHist = np.zeros([Ng, 3]) + def stateRhs(fv, dfv): + rhs = np.array([fv[1], fv[2], -0.5 * fv[2] * fv[0]]) + J = sps.csr_matrix([[0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [-0.5 * fv[2], 0.0, -0.5 * fv[0]]]) + return rhs, J.dot(dfv) + + Niter = 100 + threshold = 1e-15 + for iter in range(Niter): + fv = np.copy(fv0) + dfv = np.copy(dfv0) + fvHist[0] = np.copy(fv0) + for n in range(1, Ng): + k1, dk1 = stateRhs(fv, dfv) + k2, dk2 = stateRhs(fv + 0.5 * dx * k1, dfv + 0.5 * dx * dk1) + k3, dk3 = stateRhs(fv + 0.5 * dx * k2, dfv + 0.5 * dx * dk2) + k4, dk4 = stateRhs(fv + dx * k3, dfv + dx * dk3) + fv += dx / 6. * (k1 + 2. * k2 + 2. * k3 + k4) + dfv += dx / 6. * (dk1 + 2. * dk2 + 2. * dk3 + dk4) + fvHist[n] = np.copy(fv) + res = fv[1] - 1.0 + if (abs(res) < threshold): + print(iter, abs(res)) + break + else: + fv0[-1] -= res / dfv[1] + f = fvHist[:, 0] + + temp = np.append(eta[:,np.newaxis].T, fvHist.T, axis=0).T + # np.savetxt("blasius.txt", temp) + return temp + +def cubicSplineInterp(x, y): + from scipy.interpolate import splrep, BSpline + t, c, k = splrep(x, y, k = 3) + return BSpline(t, c, k) + +def initial_condition(g, mach_number=1.0 / 343.0, gamma=1.4, Re = 1.16e6): + x = g.xyz[0][:,:,:,0] + y = g.xyz[0][:,:,:,1] + + xmin = np.amin(x) + delta = np.sqrt((x - xmin) / Re / mach_number + 1.0) + eta = y / delta + print(eta[0, 10, -1], eta[-1, 10, -1]) + blasiusTable = solve_blasius(1.5 * np.amax(eta)) + uTable = mach_number * blasiusTable[:, 2] + vtTable = 0.5 * (blasiusTable[:, 0] * blasiusTable[:, 2] - blasiusTable[:, 1]) + uFunc = cubicSplineInterp(blasiusTable[:, 0], uTable) + vtFunc = cubicSplineInterp(blasiusTable[:, 0], vtTable) + + u0 = uFunc(eta) + v0 = vtFunc(eta) / Re / delta + p = 1.0 / gamma + + mask = (eta < 0.0) + u0[mask] = 0.0 + v0[mask] = 0.0 + + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,0] = 1.0 + s.q[0][:,:,:,1:4] = 0.0 + s.q[0][:,:,:,1] = u0 + s.q[0][:,:,:,2] = v0 + s.q[0][:,:,:,4] = p + return s.fromprimitive() + +def initial_condition_from_exp(g, expFilename, Lx = 5.0, a0 = 343.0, gamma = 1.4, Re = 1.1588e+05): + x = g.xyz[0][:,:,:,0] + y = g.xyz[0][:,:,:,1] + + expData = np.loadtxt(expFilename) + ymax = expData[-1, 0] / Lx + uFunc = cubicSplineInterp(expData[:, 0], expData[:, 1]) + vtFunc = cubicSplineInterp(expData[:, 0], expData[:, 2]) + + u0 = uFunc(y * Lx) / a0 + v0 = vtFunc(y * Lx) / a0 + p = 1.0 / gamma + + mask = (y < 0.0) + u0[mask] = 0.0 + v0[mask] = 0.0 + + u0[u0 <= 0.0] = 0.0 + v0[v0 <= 0.0] = 0.0 + u0[y > ymax] = expData[-1, 1] / a0 + v0[y > ymax] = expData[-1, 2] / a0 + + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,0] = 1.0 + s.q[0][:,:,:,1:4] = 0.0 + s.q[0][:,:,:,1] = u0 + s.q[0][:,:,:,2] = v0 + s.q[0][:,:,:,4] = p + return s.fromprimitive() + +if __name__ == '__main__': + Lx = 5.0 # mm + a0 = 343.0 # m/s + gamma = 1.4 + nu0 = 1.48e-5 # m2/s + Re = Lx * 1e-3 * a0 / nu0 + print("Reynolds number: %.5E" % Re) + expFile = 'UV.4.5v_0msC.txt' + + dip_range = np.array([0.0, 15.0, 7.5]) + g = grid([501, 201], Lx, dip_range, mapping_type='geom') + g.save('DeformingWall2D.xyz') + s = initial_condition_from_exp(g, expFile, Lx, a0, gamma, Re) + # s = initial_condition(g, mach_number = 0.1, Re = 23175.7) + s.save('DeformingWall2D.ic.q') + s.save('DeformingWall2D.target.q') diff --git a/examples/FiveBlockMesh/config.py b/examples/FiveBlockMesh/config.py index f07f371b..750f4199 100644 --- a/examples/FiveBlockMesh/config.py +++ b/examples/FiveBlockMesh/config.py @@ -71,8 +71,8 @@ def target_mollifier(g): else: imin, imax = p3d.find_extents(x, 0., x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -100,8 +100,8 @@ def control_mollifier(g): else: imin, imax = p3d.find_extents(x, 0., x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/FiveBlockMesh/config.py2 b/examples/FiveBlockMesh/config.py2 new file mode 100644 index 00000000..f07f371b --- /dev/null +++ b/examples/FiveBlockMesh/config.py2 @@ -0,0 +1,129 @@ +#!/usr/bin/env python +import numpy as np +from scipy.optimize import fsolve +import numpy.random as random + +import plot3dnasa as p3d + +EPSILON = np.finfo(float).eps + +def grid(numX,numY): + x_min = -14. + x_max = 14. + y_min = -10. + y_max = 10. + Lx, Ly = x_max-x_min, y_max-y_min + + size = [[numX,numY], + [numY,numX], + [numX,numY], + [numY,numX], + [numX,numY]] + g = p3d.Grid().set_size(size,True) + + x0 = np.linspace(x_min,x_max, g.size[0,0]) + y0 = np.linspace(y_min,y_max, g.size[0,1]) + + for i in range(5): + g.xyz[i][:,:,0,2] = 0. + # center, N, W, S, E + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x0, y0)) + g.xyz[1][:,:,0,:2] = np.transpose(np.meshgrid(-x0, y0+Ly),[1,2,0]) + g.xyz[2][:,:,0,:2] = np.transpose(np.meshgrid(-Lx-x0, -y0)) + g.xyz[3][:,:,0,:2] = np.transpose(np.meshgrid(x0, -y0-Ly),[1,2,0]) + g.xyz[4][:,:,0,:2] = np.transpose(np.meshgrid(Lx+x0, y0)) + + return g + +def initial_condition(g, mach_number=1.3, gamma=1.4): + x0, sigma = -7.0, 1.0 + from math import atan + pi = atan(1.0)*4.0 + x = g.xyz[0][:,0,0,0] + + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i in range(np.size(g.xyz[0],1)): + s.q[0][:,i,0,1] += 1.0/np.sqrt(2.0*pi)/sigma*np.exp( -(x-x0)**2/2.0/sigma/sigma ) + return s.fromprimitive(gamma) + +def target_mollifier(g): + x_min = -1. + x_max = 1. + y_min = -10. + y_max = 10. + f = p3d.Function().copy_from(g) + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + y = g.xyz[i][0,:,0,1] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.tanh_support(y, y_min, y_max, 5., 0.2) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + if i==0: + imin, imax = p3d.find_extents(-x, 0., -x_min) + jmin, jmax = p3d.find_extents(-y, y_min, y_max) + else: + imin, imax = p3d.find_extents(x, 0., x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 5. + y_min = -2. + y_max = 2. + f = p3d.Function().copy_from(g) + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + y = g.xyz[i][0,:,0,1] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.cubic_bspline_support(y, y_min, y_max) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + if i==0: + imin, imax = p3d.find_extents(-x, 0., -x_min) + jmin, jmax = p3d.find_extents(-y, y_min, y_max) + else: + imin, imax = p3d.find_extents(x, 0., x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + for i, fi in enumerate(f.f): + fi[:,:,:,0] = s.toprimitive().q[i][:,:,:,4] + return f + + +if __name__ == '__main__': + g = grid(101,101) + output_prefix = 'FiveBlockMesh' + g.save(output_prefix + '.xyz') +# initial_condition(g).save(output_prefix + '.ic.q') +# control_mollifier(g).save(output_prefix + '.control_mollifier.f') +# target_mollifier(g).save(output_prefix + '.target_mollifier.f') +# target_state(g).save('MultiblockJet.target.q') +# initial_condition(g).save('MultiblockJet.ic.q') +# gi = extract_inflow(g) +# gi.save('MultiblockJet.inflow.xyz') +# modes = eigenmodes() +# for i, mode in enumerate(modes): +# sr, si = inflow_perturbations(gi, mode) +# sr.save('MultiblockJet-%02d.eigenmode_real.q' % (i + 1)) +# si.save('MultiblockJet-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/KolmogorovFlow/config.py b/examples/KolmogorovFlow/config.py index 8f8a84bc..74b674e7 100644 --- a/examples/KolmogorovFlow/config.py +++ b/examples/KolmogorovFlow/config.py @@ -61,8 +61,8 @@ def target_mollifier(g, alpha = 1.0): g.xyz[0][:,j,0,0], x_min, x_max, 10., 0.3) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g,alpha=1.0): @@ -81,8 +81,8 @@ def control_mollifier(g,alpha=1.0): # g.xyz[0][i,:,0,1], y_min, y_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f if __name__ == '__main__': diff --git a/examples/KolmogorovFlow/config.py2 b/examples/KolmogorovFlow/config.py2 new file mode 100644 index 00000000..8f8a84bc --- /dev/null +++ b/examples/KolmogorovFlow/config.py2 @@ -0,0 +1,94 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def grid(size,alpha=1.0): + x_min = 0.0 + x_max = alpha + y_min = 0.0 + y_max = 1.0 + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0] + 1)[:-1] + y = np.linspace(y_min, y_max, g.size[0,1] + 1)[:-1] + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def initial_condition(g, mach_number=0.1, gamma=1.4): + y = g.xyz[0][:,:,:,1] + x = g.xyz[0][:,:,:,0] + + temp = np.zeros_like(g.xyz[0][:,:,:,0]) + temp = 1.0 / (gamma-1) + + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,0] = 1.0 + s.q[0][:,:,:,1:4] = 0.0 + s.q[0][:,:,:,2] = mach_number * np.cos(2.0*np.pi*(x-0.1*np.sin(2.0*np.pi*y))) + s.q[0][:,:,:,4] = 1.0 / gamma + return s.fromprimitive() + +def random_solution(g,time=0.0,timestep=0): + + gamma = 1.4 + s = p3d.Solution().copy_from(g).quiescent(gamma) + n = s.get_size(0) + s.q[0][:,:,0,0] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 1.0 + s.q[0][:,:,0,1] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 0.0 + s.q[0][:,:,0,2] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 0.1 + s.q[0][:,:,0,4] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-2 + 1./(gamma-1.) + s.q[0][:,:,0,4] *= (gamma-1.)/gamma * s.q[0][:,:,0,0] + + s.time = time + s._format.aux_header[0] = timestep + + return s.fromprimitive(gamma) + +def target_mollifier(g, alpha = 1.0): + x = g.xyz[0][:,:,:,0] + y = g.xyz[0][:,:,:,1] + x_min = 0.6 * alpha + x_max = 1.0 * alpha + y_min = 0.0 + y_max = 1.0 + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + #for i in range(n[0]): + # f.f[0][i,:,0,0] *= p3d.tanh_support( + # g.xyz[0][i,:,0,1], y_min, y_max, 40., 0.2) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.tanh_support( + g.xyz[0][:,j,0,0], x_min, x_max, 10., 0.3) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g,alpha=1.0): + x_min = 0.0 * alpha + x_max = 0.6 * alpha + y_min = 0. + y_max = 1. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.tanh_support( + g.xyz[0][:,j,0,0], x_min, x_max, 10., 0.3) + #for i in range(n[0]): + # f.f[0][i,:,0,0] *= p3d.cubic_bspline_support( + # g.xyz[0][i,:,0,1], y_min, y_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +if __name__ == '__main__': + g = grid([256,256],alpha=0.9) + g.save('KolmogorovFlow.xyz') + initial_condition(g,mach_number=0.05).save('KolmogorovFlow.ic.q') + target_mollifier(g,alpha=0.9).save('KolmogorovFlow.target_mollifier.f') + control_mollifier(g,alpha=0.9).save('KolmogorovFlow.control_mollifier.f') + #random_solution(g).save('ChannelFlow.ic.q') diff --git a/examples/MultiblockAcousticMonopole/config.py b/examples/MultiblockAcousticMonopole/config.py index e0e2409a..15260a73 100644 --- a/examples/MultiblockAcousticMonopole/config.py +++ b/examples/MultiblockAcousticMonopole/config.py @@ -48,8 +48,8 @@ def target_mollifier(g): fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) imin, imax = p3d.find_extents(x, x_min, x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -73,8 +73,8 @@ def control_mollifier(g): fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) imin, imax = p3d.find_extents(x, x_min, x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/MultiblockAcousticMonopole/config.py2 b/examples/MultiblockAcousticMonopole/config.py2 new file mode 100644 index 00000000..e0e2409a --- /dev/null +++ b/examples/MultiblockAcousticMonopole/config.py2 @@ -0,0 +1,101 @@ +#!/usr/bin/env python +import numpy as np +from scipy.optimize import fsolve +import numpy.random as random + +import plot3dnasa as p3d + +EPSILON = np.finfo(float).eps + +def grid(numX,numY): + x_min = -14. + x_max = 14. + y_min = -14. + y_max = 14. + size = [[numX,numY],[numX,numY]] + g = p3d.Grid().set_size(size,True) + x1 = np.linspace(x_min, 0., g.size[0,0]) + x2 = np.linspace(0., x_max, g.size[1,0]) + y = np.linspace(y_min, y_max, g.size[0,1]) + g.xyz[0][:,:,0,2] = 0. + g.xyz[1][:,:,0,2] = 0. + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x1, y)) + g.xyz[1][:,:,0,:2] = np.transpose(np.meshgrid(x2, y)) + return g + +def initial_condition(g, mach_number=1.3, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + return s.fromprimitive(gamma) + +def target_mollifier(g): + x_min = -3. + x_max = 3. + y_min = -1. + y_max = 1. + f = p3d.Function().copy_from(g) + y = g.xyz[0][0,:,0,1] + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.tanh_support(y, y_min, y_max, 5., 0.2) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + imin, imax = p3d.find_extents(x, x_min, x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = -3. + x_max = 3. + y_min = 2. + y_max = 4. + f = p3d.Function().copy_from(g) + y = g.xyz[0][0,:,0,1] + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.cubic_bspline_support(y, y_min, y_max) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + imin, imax = p3d.find_extents(x, x_min, x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + for i, fi in enumerate(f.f): + fi[:,:,:,0] = s.toprimitive().q[i][:,:,:,4] + return f + + +if __name__ == '__main__': + g = grid(101,201) + g.save('MultiblockAcousticMonopole.xyz') + initial_condition(g).save('MultiblockAcousticMonopole.ic.q') + control_mollifier(g).save('MultiblockAcousticMonopole.control_mollifier.f') + target_mollifier(g).save('MultiblockAcousticMonopole.target_mollifier.f') +# target_state(g).save('MultiblockJet.target.q') +# initial_condition(g).save('MultiblockJet.ic.q') +# gi = extract_inflow(g) +# gi.save('MultiblockJet.inflow.xyz') +# modes = eigenmodes() +# for i, mode in enumerate(modes): +# sr, si = inflow_perturbations(gi, mode) +# sr.save('MultiblockJet-%02d.eigenmode_real.q' % (i + 1)) +# si.save('MultiblockJet-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/MultiblockJet/config.py b/examples/MultiblockJet/config.py index e104b1b8..757ae545 100644 --- a/examples/MultiblockJet/config.py +++ b/examples/MultiblockJet/config.py @@ -124,8 +124,8 @@ def find_eigenvalue(self, initial_guess, max_iterations=200, y = self.newton_raphson_func(x) it = it + 1 if it >= max_iterations: - print "Newton-Raphson failed: initial guess = ", initial_guess, \ - ", current guess = ", x, ", current function = ", abs(y) + print("Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y)) self.alpha = x.real - 1.j * abs(x.imag) return self @@ -465,7 +465,7 @@ def eigenmodes(mach_number=1.3, theta_j=0.04, show_progress=True): modes = [[InstabilityMode() for n_ in n] for St_ in St] if show_progress: from progressbar import ProgressBar, Percentage, Bar, ETA - print 'Computing eigenmodes:' + print('Computing eigenmodes:') p = ProgressBar(widgets = [Percentage(), ' ', Bar('=', left = '[', right = ']'), ' ', ETA()], maxval = alpha.size).start() @@ -551,9 +551,9 @@ def target_mollifier(g): fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) kmin, kmax = p3d.find_extents(z, z_min, z_max) imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'targetRegion.' + block_code[i], 'COST_TARGET', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f def control_mollifier(g): @@ -581,22 +581,22 @@ def control_mollifier(g): for i in range(n[i][1])) imax = max(np.where(r[:,i] <= r_max)[0][-1] + 2 for i in range(n[i][1])) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'controlRegion.' + block_code[i], 'ACTUATOR', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f def mean_pressure(s): s_prim = s.toprimitive() f = p3d.Function().copy_from(s_prim) - print (np.shape(f.f)) + print((np.shape(f.f))) for i, fi in enumerate(f.f): print (i) - print (fi.shape) - print (np.min(s.q[i][:,:,:,4]), np.max(s.q[i][:,:,:,4])) + print((fi.shape)) + print((np.min(s.q[i][:,:,:,4]), np.max(s.q[i][:,:,:,4]))) #print (s.toprimitive().q[i].shape) fi[:,:,:,0] = s_prim.q[i][:,:,:,4] - print (np.min(fi), np.max(fi)) + print((np.min(fi), np.max(fi))) return f def state_mollifier(g): diff --git a/examples/MultiblockJet/config.py2 b/examples/MultiblockJet/config.py2 new file mode 100644 index 00000000..e104b1b8 --- /dev/null +++ b/examples/MultiblockJet/config.py2 @@ -0,0 +1,698 @@ +#!/usr/bin/env python +import numpy as np +from scipy.optimize import fsolve +import numpy.random as random + +import plot3dnasa as p3d + +EPSILON = np.finfo(float).eps + +class InstabilityMode: + + def __init__(self, n=0, omega=0., theta=1., mach_number=0., + r_nozzle=0.5, gamma=1.4): + self.n = n + self.omega = omega + self.theta = theta + self.mach_number = mach_number + self.r_nozzle = r_nozzle + self.gamma = gamma + + def update(self): + self._temperature_ratio = 1. / (1. + 0.5 * (self.gamma - 1.) * + self.mach_number ** 2) + self._u_j = self.mach_number * np.sqrt(self._temperature_ratio) + return self + + def set_domain(self, r, r_lower, r_match, r_upper): + self._r = r + i_lower = np.argmin(np.abs(self._r - r_lower)) + i_match = np.argmin(np.abs(self._r - r_match)) + i_upper = np.argmin(np.abs(self._r - r_upper)) + self._num_steps_inner = i_match - i_lower + self._num_steps_outer = i_upper - i_match + self._r_lower = self._r[i_lower] + self._r_match = self._r[i_match] + self._r_upper = self._r[i_upper] + return self + + def mean_flow(self, r): + u = 0.5 * (1. + np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle))) + u_dot = -0.125 / self.theta * (1. - np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle)) ** 2) * ( + self.r_nozzle / (r + EPSILON) ** 2 + 1. / self.r_nozzle) + # u, \rho, a, du/dr, d\rho/dr + mean_flow = np.array([np.empty_like(r) for i in range(5)]) + mean_flow[0] = self.mach_number * np.sqrt(self._temperature_ratio) * u + mean_flow[1] = 1. / self._temperature_ratio / ( + 0.5 * (self.gamma - 1.) * u * (1. - u) * self.mach_number ** 2 + + u + (1. - u) / self._temperature_ratio) + mean_flow[2] = np.sqrt(1. / mean_flow[1]) + mean_flow[3] = self.mach_number * np.sqrt(self._temperature_ratio) * \ + u_dot + mean_flow[4] = -self._temperature_ratio * mean_flow[1] ** 2 * u_dot * ( + 0.5 * (self.gamma - 1.) * (1. - 2. * u) * self.mach_number ** 2 + + 1. - 1. / self._temperature_ratio) + return mean_flow + + def rayleigh_rhs(self, r, p_hat, alpha): + u, rho, a, u_r, rho_r = self.mean_flow(r) + return np.array([p_hat[1], + - (1. / r - rho_r / rho + 2. * alpha / + (self.omega - alpha * u) * u_r) * p_hat[1] - + ((self.omega - alpha * u) ** 2 / a ** 2 - + self.n ** 2 / r ** 2 - alpha ** 2) * p_hat[0]]) + + def inner_solution(self, r, alpha): + import scipy.special + eta = np.sqrt((self.omega - alpha * self._u_j) ** 2 / + self._temperature_ratio - alpha ** 2) + return np.array([scipy.special.jn(self.n, eta * r), + eta * 0.5 * (scipy.special.jn(self.n - 1, eta * r) - + scipy.special.jn(self.n + 1, eta * r))]) + + def outer_solution(self, r, alpha): + import scipy.special + eta = np.sqrt(self.omega ** 2 - alpha ** 2) + return np.array([scipy.special.hankel1(self.n, + np.sign(eta.imag) * eta * r), + np.sign(eta.imag) * eta * 0.5 * ( + scipy.special.hankel1(self.n - 1, + np.sign(eta.imag) * + eta * r) - + scipy.special.hankel1(self.n + 1, + np.sign(eta.imag) * + eta * r))]) + + def newton_raphson_func(self, alpha): + from scipy.integrate import ode + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(alpha) + # Inner solution + integrator.set_initial_value(self.inner_solution(self._r_lower, alpha), + self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + integrator.integrate(integrator.t + dr) + inner_solution = integrator.y + # Outer solution + integrator.set_initial_value(self.outer_solution(self._r_upper, alpha), + self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + integrator.integrate(integrator.t - dr) + outer_solution = integrator.y + if abs(outer_solution[0] / inner_solution[0]) < 1e-6: + return inner_solution[1] - outer_solution[1] * \ + inner_solution[0] / outer_solution[0] + return inner_solution[1] * outer_solution[0] / inner_solution[0] - \ + outer_solution[1] + + def find_eigenvalue(self, initial_guess, max_iterations=200, + tolerance=1e-10): + x = initial_guess + y = self.newton_raphson_func(x) + it = 1 + while abs(y) > tolerance and it <= max_iterations: # Newton-Raphson + dx = random.uniform(1e-10, 1e-8) + 1j * \ + random.uniform(1e-10, 1e-8) # step size for derivative + x = x - dx * y / (self.newton_raphson_func(x + dx) - y) + y = self.newton_raphson_func(x) + it = it + 1 + if it >= max_iterations: + print "Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y) + self.alpha = x.real - 1.j * abs(x.imag) + return self + + def find_eigenfunction(self, tolerance=1e-8): + from scipy.integrate import ode + from scipy.interpolate import interp1d + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(self.alpha) + p_hat = np.array([np.empty_like(self._r) for i in range(2)], + dtype='complex128') + i_lower = np.argmin(np.abs(self._r - self._r_lower)) + p_hat[:,:i_lower] = self.inner_solution(self._r[:i_lower], self.alpha) + i = i_lower + integrator.set_initial_value(self.inner_solution( + self._r_lower, self.alpha), self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t + dr) + i += 1 + p_hat[:,i] = integrator.y + i_upper = np.argmin(np.abs(self._r - self._r_upper)) + p_hat[:,i_upper:] = self.outer_solution(self._r[i_upper:], self.alpha) + i = i_upper + integrator.set_initial_value(self.outer_solution( + self._r_upper, self.alpha), self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t - dr) + i -= 1 + outer_solution = integrator.y + scaling_factor = integrator.y[0] / p_hat[0,i] + scaling_factor_inverse = 1. / scaling_factor + if abs(scaling_factor) < 1e-6: + p_hat[:,i+1:] *= scaling_factor_inverse + else: + p_hat[:,:i+1] *= scaling_factor + assert abs(p_hat[1,i] - integrator.y[1]) < tolerance + self.p_hat_dot = interp1d(self._r, p_hat[1,:], kind='linear') + self.p_hat = interp1d(self._r, p_hat[0,:], kind='linear') + return self + + def get_eigenmode(self, r): + u, rho, a, u_r, rho_r = self.mean_flow(r) + p_hat = self.p_hat(r) + p_hat_r = self.p_hat_dot(r) + omega = self.omega - self.alpha * u + u_hat_r = 1. / (1.j * rho * omega) * p_hat_r + u_hat_x = self.alpha * p_hat / (rho * omega) + \ + u_hat_r / (1.j * omega) * u_r + rho_hat = p_hat / a ** 2 + u_hat_r / (1.j * omega) * rho_r + return np.array([rho_hat, + rho * u_hat_r, + self.n * p_hat / (r * omega + EPSILON), + rho_hat * u + rho * u_hat_x, + p_hat / (self.gamma - 1.) + 0.5 * rho_hat * u ** 2 + + rho * u * u_hat_x]) + +def mesh_segment(n, x_min, x_max, dx_min, dx_max=None): + """ If dx_max is None, returns a one-sided stretched mesh from x_min + to x_max with minimum spacing dx_min at x_min. Otherwise, returns a + two-sided stretched mesh with spacing dx_min and dx_max at x_min and + x_max, respectively. + """ + from scipy.optimize import curve_fit + if dx_max is None: + f = lambda x, sigma: np.sinh(sigma * x) / np.sinh(sigma) + sigma = fsolve(lambda x: ((x_max - x_min) * f(1. / (n - 1.), x) - + dx_min) ** 2, 2.) + return x_min + (x_max - x_min) * f(np.linspace(0., 1., n), sigma) + f = lambda xi, a, b, c, d: a + b * np.tanh(c * (xi - d)) + a, b, c, d = curve_fit(f, np.array([0., 1. / (n - 1), 1. - + 1. / (n - 1), 1.]), + np.array([x_min, x_min + dx_min, + x_max - dx_max, x_max]))[0] + return f(np.linspace(0., 1., n), a, b, c, d) + +def axial_coordinate(z_min=-9., z_max=34., z_physical=24., num_axial=512, + num_inflow_sponge=48, num_outflow_sponge=28, + num_potential_core=240, potential_core_length=8., + dz_exit=0.04, dz_min=0.01, dz_physical_outflow=0.22): + z = -mesh_segment(num_inflow_sponge + 1, 0., -z_min, dz_exit)[::-1] + z = np.append(z[:-1], mesh_segment(num_potential_core + 1, 0., + potential_core_length, dz_exit, dz_min)) + z = np.append(z[:-1], mesh_segment( + num_axial - (num_inflow_sponge + num_outflow_sponge + + num_potential_core), potential_core_length, z_physical, + dz_min, dz_physical_outflow)) + z = np.append(z[:-1], mesh_segment(num_outflow_sponge + 1, z_physical, + z_max, dz_physical_outflow)) + return z + +def dc_func(x, n, num_const_dr, dr_min, a_inner, sigma): + s = np.linspace(0., 1., n) + dc = np.empty_like(s) + dc[:num_const_dr] = x * (0.5 - 0.5 * a_inner) / (n + 1) + dc[-num_const_dr:] = dr_min + y = -np.tanh((s[num_const_dr:-num_const_dr] - 0.5) / sigma) + dc[num_const_dr:-num_const_dr] = dc[-1] + (dc[0] - dc[-1]) * \ + (y - y.min()) / (y.max() - y.min()) + c = np.cumsum(dc) + 0.5 * a_inner - dc[0] + return (c[-1] - 0.5) ** 2 + +def nozzle_quadrant(grid_size, num_const_dr=4, a_inner=0.24, + p_inner=1.12, dr_min=0.005): + theta = np.linspace(0., np.pi / 2, grid_size[1]) + s = np.linspace(0., 1., grid_size[0]) + p = np.empty_like(s) + p[:num_const_dr] = p_inner + p[-num_const_dr:] = 2. + p[num_const_dr:-num_const_dr] = np.linspace(p_inner, 2., grid_size[0] - + 2 * num_const_dr) + sigma = 0.2 + xi = fsolve(dc_func, 1.2, args=(grid_size[0], num_const_dr, + dr_min, a_inner, sigma)) + dc = np.empty_like(s) + dc[:num_const_dr] = xi * (0.5 - 0.5 * a_inner) / (grid_size[0] + 1) + dc[-num_const_dr:] = dr_min + y = -np.tanh((s[num_const_dr:-num_const_dr] - 0.5) / sigma) + dc[num_const_dr:-num_const_dr] = dc[-1] + (dc[0] - dc[-1]) * \ + (y - y.min()) / (y.max() - y.min()) + c = np.cumsum(dc) + 0.5 * a_inner - dc[0] + x = np.zeros([grid_size[0], grid_size[1]]) + y = np.zeros_like(x) + for i in range(grid_size[0]): + r = c[i] / (np.cos(theta) ** p[i] + + np.sin(theta) ** p[i]) ** (1. / p[i]) + x[i,:] = r * np.cos(theta) + y[i,:] = r * np.sin(theta) + return x, y + +def near_field_quadrant(grid_size, num_const_dr=4, dr_min=0.005, r_max=12.5): + r = np.append(np.linspace( + 0.5, 0.5 + (num_const_dr - 1) * dr_min, num_const_dr), mesh_segment( + grid_size[0] - num_const_dr + 2, 0.5 + (num_const_dr - 1) * dr_min, + r_max, dr_min)[1:]) + p3d.mesh_stats(r) + r, theta = np.meshgrid(r[1:], np.linspace(0., np.pi / 2, grid_size[1])) + x = r * np.cos(theta) + y = r * np.sin(theta) + return x.T, y.T + +def complete_rotated_blocks(g): + n = g.get_size(0)[2] + for i in range(2, 5): + for k in range(n): + g.xyz[i][:,:,k,0] = -g.xyz[i-1][:,:,k,1] + g.xyz[i][:,:,k,1] = g.xyz[i-1][:,:,k,0] + g.xyz[i][:,:,:,2] = g.xyz[i-1][:,:,:,2] + return g + +def elliptic_solve(x, tol=1e-4, max_iter=2000): + y = np.zeros_like(x) + i = 0 + while np.amax(np.abs(x - y)) > tol and i < max_iter: + y[:,:] = x + x[1:-1,1:-1] = (4. * x[1:-1,1:-1] + x[:-2,1:-1] + x[2:,1:-1] + + x[1:-1,:-2] + x[1:-1,2:]) / 8. + i += 1 + return x + +def complete_inner_block(g, smoothing_tol=1e-8): + from scipy.ndimage.filters import uniform_filter + n = g.get_size(0) + g.xyz[0][0,:,0,0:2] = g.xyz[2][0,::-1,0,0:2] + g.xyz[0][-1,:,0,0:2] = g.xyz[4][0,:,0,0:2] + g.xyz[0][:,0,0,0:2] = g.xyz[3][0,:,0,0:2] + g.xyz[0][:,-1,0,0:2] = g.xyz[1][0,::-1,0,0:2] + for i in range(1, n[0] - 1): + for j in range(1, n[1] - 1): + g.xyz[0][i,j,0,0] = g.xyz[0][0,j,0,0] + i / (n[0] - 1.) * \ + (g.xyz[0][-1,j,0,0] - g.xyz[0][0,j,0,0]) + g.xyz[0][i,j,0,1] = g.xyz[0][i,0,0,1] + j / (n[1] - 1.) * \ + (g.xyz[0][i,-1,0,1] - g.xyz[0][i,0,0,1]) + g.xyz[0][:,:,0,0] = elliptic_solve(g.xyz[0][:,:,0,0], tol=smoothing_tol) + g.xyz[0][:,:,0,1] = elliptic_solve(g.xyz[0][:,:,0,1], tol=smoothing_tol) + for k in range(n[2]): + g.xyz[0][:,:,k,0:2] = g.xyz[0][:,:,0,0:2] + g.xyz[0][:,:,k,2] = g.xyz[1][0,0,k,2] + return g + +def plot_axial_spacing(z): + import matplotlib.pyplot as plt + ax = plt.subplot(111) + dz = z[1:] - z[:-1] + ax.plot(z[:-1], dz, 'ko-') + plt.show() + +def plot_radial_spacing(r): + import matplotlib.pyplot as plt + ax = plt.subplot(111) + dr = r[1:] - r[:-1] + ax.plot(r[:-1], dr, 'ko-') + plt.show() + +def plot_jacobian_continuity(g): + import matplotlib.pyplot as plt + from numpy.linalg import det + ax = plt.subplot(111) + f = p3d.compute_jacobian(g) + for k in range(5): + x = g.xyz[k][:,:,0,0] + y = g.xyz[k][:,:,0,1] + z = np.empty_like(x) + for i in range(z.shape[0]): + for j in range(z.shape[1]): + z[i,j] = 1. / det(np.reshape(f.f[k][i,j,0,:], [3, 3])) + if k == 0: + vmin = z.min() + vmax = z.max() + c = ax.contour(x, y, z, levels=np.linspace(vmin, vmax, 31)) + plt.colorbar(c) + ax.set_xlim([-0.5, 0.5]) + ax.set_ylim([-0.5, 0.5]) + ax.set_aspect('equal') + plt.show() + +def grid(num_radial_nozzle, num_radial_near_field, num_azimuthal, + num_axial=512, a_inner=0.24, p_inner=1.12, dr_min=0.005): + assert num_azimuthal % 4 == 0 + num_radial = num_radial_nozzle + num_radial_near_field + g = p3d.Grid().set_size([ + [num_azimuthal / 4, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial]], True) + x, y = nozzle_quadrant([num_radial_nozzle, num_azimuthal / 4], + a_inner=a_inner, p_inner=p_inner, dr_min=dr_min) + for k in range(num_axial): + g.xyz[1][:num_radial_nozzle,:,k,0] = x + g.xyz[1][:num_radial_nozzle,:,k,1] = y + x, y = near_field_quadrant([num_radial_near_field, num_azimuthal / 4], + dr_min=dr_min) + for k in range(num_axial): + g.xyz[1][num_radial_nozzle:,:,k,0] = x + g.xyz[1][num_radial_nozzle:,:,k,1] = y + if num_axial > 1: + z = axial_coordinate(num_axial=num_axial) + p3d.mesh_stats(z) + # plot_axial_spacing(z) + for k in range(num_axial): + g.xyz[1][:,:,k,2] = z[k] + complete_rotated_blocks(g) + for i in range(1, 5): + x = np.copy(g.xyz[i][:,:,:,0]) + g.xyz[i][:,:,:,0] = (g.xyz[i][:,:,:,0] - + g.xyz[i][:,:,:,1]) / np.sqrt(2.) + g.xyz[i][:,:,:,1] = (x + g.xyz[i][:,:,:,1]) / np.sqrt(2.) + complete_inner_block(g) + r = np.append(g.xyz[0][:,num_azimuthal/8,0,0], + g.xyz[4][1:,num_azimuthal/8,0,0]) + # plot_radial_spacing(r) + # plot_jacobian_continuity(g) + return g + +def target_state(g, mach_number=1.3, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + temperature_ratio = 1. / (1. + 0.5 * (gamma - 1.) * mach_number ** 2) + T_inf = 1./ (gamma - 1.) + u_j = mach_number * np.sqrt(temperature_ratio) + for i, xyz in enumerate(g.xyz): + z = xyz[0,0,:,2] + r = np.sqrt(xyz[:,:,0,0] ** 2 + xyz[:,:,0,1] ** 2) + condlist = [z <= 0., np.logical_and(z > 0., z < 24.), z >= 24.] + r0 = np.select(condlist, [0.5 + np.zeros_like(z), 0.04125 * z + 0.5, + 0.075 * z - 0.31]) + theta = np.select(condlist, [0.04 + np.zeros_like(z), + 0.46 * z / 24. + 0.04, 0.5]) + u = np.where(z <= 2.65, u_j + np.zeros_like(z), + u_j * np.exp(-(z - 2.65) / 25.)) + rho = np.where(z <= 0., 1. / temperature_ratio + np.zeros_like(z), + 1. + (1. / temperature_ratio - 1.) * np.exp(-0.078 * z)) + for k in range(z.size): + s.q[i][:,:,k,3] = 0.5 * u[k] * (1. + np.tanh( + 0.25 / theta[k] * (r0[k] / r - r / r0[k]))) + s.q[i][:,:,k,0] = rho[k] / (0.5 * (gamma - 1.) * s.q[i][:,:,k,3] / + u[k] * (1. - s.q[i][:,:,k,3] / u[k]) * + rho[k] * u[k] ** 2 + s.q[i][:,:,k,3] / + u[k] + rho[k] * + (1. - s.q[i][:,:,k,3] / u[k])) + return s.fromprimitive(gamma) + +def initial_condition(g, mach_number=1.3, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + temperature_ratio = 1. / (1. + 0.5 * (gamma - 1.) * mach_number ** 2) + u_j = mach_number * np.sqrt(temperature_ratio) + for i, xyz in enumerate(g.xyz): + z = xyz[0,0,:,2] + r = np.sqrt(xyz[:,:,0,0] ** 2 + xyz[:,:,0,1] ** 2) / 0.5 + condlist = [z <= 0., np.logical_and(z > 0., z < 24.), z >= 24.] + theta = 0.04 + np.where(z <= 0., np.zeros_like(z), 0.46 * z / 34.) + for k in range(z.size): + s.q[i][:,:,k,3] = 0.5 * u_j * (1. + np.tanh( + 0.25 / theta[k] * (1. / r - r))) + s.q[i][:,:,:,0] = 1. / (0.5 * (gamma - 1.) * s.q[i][:,:,:,3] / u_j * + (1. - s.q[i][:,:,:,3] / u_j) * + mach_number ** 2 + s.q[i][:,:,:,3] / u_j + + (1. - s.q[i][:,:,:,3] / u_j) / + temperature_ratio) / temperature_ratio + return s.fromprimitive(gamma) + +def plot_eigenvalues(St, alpha, u_j, theta_j): + import matplotlib.pyplot as plt + ax = plt.subplot(121) + for i in range(alpha.shape[0]): + ax.plot(St, -alpha[i,:].imag * theta_j, 'rs-', mec='r', mfc='w') + ax.set_xlim([0.35, 0.95]) + ax.set_ylim([0.05, 0.11]) + ax = plt.subplot(122) + omega = 2. * np.pi * u_j * St + for i in range(alpha.shape[0]): + ax.plot(St, omega / alpha[i,:].real / u_j, 'rs-', mec='r', mfc='w') + ax.set_xlim([0.35, 0.95]) + ax.set_ylim([0.5, 0.75]) + plt.show() + +def eigenmodes(mach_number=1.3, theta_j=0.04, show_progress=True): + u_j = InstabilityMode(mach_number=mach_number, + theta=theta_j).update().mean_flow(EPSILON)[0] + n = np.arange(1, 6) + St = np.array([0.43, 0.51, 0.61, 0.69, 0.74, 0.88]) + alpha = np.empty([n.size, St.size], dtype='complex128') + r_lower = 0.025 + r_match = 0.25 + r_upper = 3. + r = np.linspace(0., r_lower, 5001) + r = np.append(r[:-1], np.linspace(r_lower, r_match, 5001)) + r = np.append(r[:-1], np.linspace(r_match, r_upper, 5001)) + r = np.append(r[:-1], np.linspace(r_upper, 15., 5001)) + # Initialize eigenmodes. + initial_guess = 1. - 1.j + modes = [[InstabilityMode() for n_ in n] for St_ in St] + if show_progress: + from progressbar import ProgressBar, Percentage, Bar, ETA + print 'Computing eigenmodes:' + p = ProgressBar(widgets = [Percentage(), ' ', + Bar('=', left = '[', right = ']'), ' ', + ETA()], maxval = alpha.size).start() + for j, St_ in enumerate(St): + guess = initial_guess + for i, n_ in enumerate(n): + modes[j][i] = InstabilityMode( + mach_number=mach_number, theta=theta_j, n=n_, + omega=2. * np.pi * u_j * St_).update().set_domain( + r, r_lower, r_match, r_upper) + modes[j][i].find_eigenvalue(guess).find_eigenfunction() + guess = alpha[i,j] = modes[j][i].alpha + if i == 0: + initial_guess = modes[j][i].alpha + if show_progress: + p.update(i + n.size * j) + if show_progress: + p.finish() + # plot_eigenvalues(St, alpha, u_j, theta_j) + return modes + +def extract_inflow(g, num_inflow_sponge=49): + n = g.get_size() + n[:,2] = num_inflow_sponge + gi = p3d.Grid().set_size(n, True) + for i, xyz in enumerate(g.xyz): + gi.xyz[i] = xyz[:,:,:num_inflow_sponge,:] + return gi + +def inflow_perturbations(g, modes): + phi_p = 2. * np.pi * random.rand(len(modes)) + phi_n = 2. * np.pi * random.rand(len(modes)) + sr = p3d.Solution().copy_from(g) + si = p3d.Solution().copy_from(g) + sr._format.aux_header[1] = si._format.aux_header[1] = modes[0].omega + for i in range(g.nblocks): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + theta = np.arctan2(g.xyz[i][:,:,0,1], g.xyz[i][:,:,0,0]) + z = g.xyz[i][0,0,:,2] + si.q[i].fill(0.) + sr.q[i].fill(0.) + for j, mode in enumerate(modes): + q = mode.get_eigenmode(r) + n = mode.n + for l in range(q.shape[0]): + if l == 2: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) - \ + np.exp(-1.j * n * theta + phi_n[j]) + else: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) + \ + np.exp(-1.j * n * theta + phi_n[j]) + u = q[1] * np.cos(theta) - q[2] * np.sin(theta) + v = q[1] * np.sin(theta) + q[2] * np.cos(theta) + q[1] = u + q[2] = v + for l in range(q.shape[0]): + for k, z_ in enumerate(z): + sr.q[i][:,:,k,l] += np.real( + q[l] * np.exp(1.j * mode.alpha * z_)) + si.q[i][:,:,k,l] += np.imag( + q[l] * np.exp(1.j * mode.alpha * z_)) + return sr, si + +def target_mollifier(g): + z_min = 0. + z_max = 24. + r_min = 7. + r_max = 9. + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.tanh_support(z, z_min, z_max, 40., 0.2) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion.' + block_code[i], 'COST_TARGET', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +def control_mollifier(g): + z_min = 1. + z_max = 3. + r_min = 0.3 + r_max = 0.7 + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.tanh_support(z, z_min, z_max, 16., 0.2) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.tanh_support(r[:,k], r_min, r_max, 20., 0.2) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin = min(np.where(r[:,i] >= r_min)[0][0] + for i in range(n[i][1])) + imax = max(np.where(r[:,i] <= r_max)[0][-1] + 2 + for i in range(n[i][1])) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion.' + block_code[i], 'ACTUATOR', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +def mean_pressure(s): + s_prim = s.toprimitive() + f = p3d.Function().copy_from(s_prim) + print (np.shape(f.f)) + for i, fi in enumerate(f.f): + print (i) + print (fi.shape) + print (np.min(s.q[i][:,:,:,4]), np.max(s.q[i][:,:,:,4])) + #print (s.toprimitive().q[i].shape) + fi[:,:,:,0] = s_prim.q[i][:,:,:,4] + print (np.min(fi), np.max(fi)) + return f + +def state_mollifier(g): + z_min = 0.95 + z_max = 5.5 + r_min = 0.75 + r_max = 2.0 + z_rmax = 5.0 + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + + scaled_z = 2.0*(z-z_min)/(z_max-z_min) - 1.0 + z_factor = np.tanh( 40.0 * ( scaled_z + 1.0 ) ) + z_factor -= np.tanh( 2.0 * ( scaled_z - 1.0 ) ) + + slope_min, slope_max = 2.0, 10.0 + r_slope = np.array( [ slope_max - (slope_max - slope_min) * np.sin( 0.5*np.pi*(zk-z_min)/(z_rmax-z_min) ) if (zk<=z_rmax) else slope_min for zk in z] ) + + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][2]): + zk = z[k] + #if ((zk-1. < z_min) or (zk-1. > z_max)): + # fi[:,:,k,0] *= 0. + # continue + rk = r_min + (r_max-r_min) * np.sin(0.5*np.pi*(zk-z_min)/(z_rmax-z_min)) if zk<=z_rmax else r_max + slopek = r_slope[k] + r_factor = p3d.tanh_support(r, -rk, rk, slopek, 0.0, False) + + fi[:,:,k,0] *= r_factor + fi[:,:,k,0] *= z_factor[k] + + fmax = 0.0 + for fi in f.f: + fmax = max(fmax,np.amax(fi)) + for fi in f.f: + fi /= fmax + return f + +# def random_adjoint_condition(g, time, timestep, center, width, Nmodes=1): +# s = p3d.Solution().copy_from(g).quiescent(gamma) +# amp = 2. * np.random.rand(Nmodes,3) - 1. +# xc, yc, zc = center +# wr, wz = width +# rc = np.sqrt(xc**2 + yc**2) +# +# rho_amp = 2. * np.random.rand() - 1. +# rho_phase = 2. * np.pi * np.random.rand(2) +# rhoE_amp = 2. * np.random.rand() - 1. +# rhoE_phase = 2. * np.pi * np.random.rand(2) +# A_amp = 2. * np.random.rand(Nmodes,3,2) - 1. +# A_phase = 2. * np.pi * np.random.rand(Nmodes,3,2) +# +# s.q[:] *= 0.0 +# for i, xyz in enumerate(g.xyz): +# z = xyz[0,0,:,2] +# r = np.sqrt(xyz[:,:,0,0] ** 2 + xyz[:,:,0,1] ** 2) / 0.5 +# x, y = xyz[:,:,0,0], xyz[:,:,0,1] +# +# mollifier = np.exp( - 0.5*(r-rc)**2/wr/wr - 0.5 * (z-zc)**2/wz/wz ) +# +# for k in range(z.size): +# s.q[i][:,:,k,0] = mollifier * rho_amp * np.sin( np.pi * (x-xc) / wr + rho_phase[0] ) * +# np.sin( np.pi * (y-yc) / wr + rho_phase[1] ) +# s.q[i][:,:,k,4] = mollifier * rhoE_amp * np.sin( np.pi * (x-xc) / wr + rhoE_phase[0] ) * +# np.sin( np.pi * (y-yc) / wr + rhoE_phase[1] ) +# s.q[i][:,:,k,3] = 0.5 * u_j * (1. + np.tanh( +# 0.25 / theta[k] * (1. / r - r))) +# s.q[i][:,:,:,0] = 1. / (0.5 * (gamma - 1.) * s.q[i][:,:,:,3] / u_j * +# (1. - s.q[i][:,:,:,3] / u_j) * +# mach_number ** 2 + s.q[i][:,:,:,3] / u_j + +# (1. - s.q[i][:,:,:,3] / u_j) / +# temperature_ratio) / temperature_ratio +# +# s.time = time +# s._format.aux_header[0] = timestep +# +# return s.fromprimitive(gamma) + +if __name__ == '__main__': + g = grid(60, 196, 132, a_inner=0.24, p_inner=1.08634735266) + g.save('MultiblockJet.xyz') + control_mollifier(g).save('MultiblockJet.control_mollifier.f') + target_mollifier(g).save('MultiblockJet.target_mollifier.f') +# target_state(g).save('MultiblockJet.target.q') +# initial_condition(g).save('MultiblockJet.ic.q') +# gi = extract_inflow(g) +# gi.save('MultiblockJet.inflow.xyz') +# modes = eigenmodes() +# for i, mode in enumerate(modes): +# sr, si = inflow_perturbations(gi, mode) +# sr.save('MultiblockJet-%02d.eigenmode_real.q' % (i + 1)) +# si.save('MultiblockJet-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/MultiblockJetCoflow/config.py b/examples/MultiblockJetCoflow/config.py index 1a690bdd..c62cb013 100644 --- a/examples/MultiblockJetCoflow/config.py +++ b/examples/MultiblockJetCoflow/config.py @@ -128,8 +128,8 @@ def find_eigenvalue(self, initial_guess, max_iterations=200, y = self.newton_raphson_func(x) it = it + 1 if it >= max_iterations: - print "Newton-Raphson failed: initial guess = ", initial_guess, \ - ", current guess = ", x, ", current function = ", abs(y) + print("Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y)) self.alpha = x.real - 1.j * abs(x.imag) return self @@ -450,7 +450,7 @@ def eigenmodes(M1=1.5, M2=0.2, theta_j=0.04, show_progress=True): modes = [[InstabilityMode() for n_ in n] for St_ in St] if show_progress: from progressbar import ProgressBar, Percentage, Bar, ETA - print 'Computing eigenmodes:' + print('Computing eigenmodes:') p = ProgressBar(widgets = [Percentage(), ' ', Bar('=', left = '[', right = ']'), ' ', ETA()], maxval = alpha.size).start() @@ -536,9 +536,9 @@ def target_mollifier(g): fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) kmin, kmax = p3d.find_extents(z, z_min, z_max) imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'targetRegion.' + block_code[i], 'COST_TARGET', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f def control_mollifier(g): @@ -566,9 +566,9 @@ def control_mollifier(g): for i in range(n[i][1])) imax = max(np.where(r[:,i] <= r_max)[0][-1] + 2 for i in range(n[i][1])) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'controlRegion.' + block_code[i], 'ACTUATOR', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f def axisymmetric_grid(num_axial=512, r_max=12.5): diff --git a/examples/MultiblockJetCoflow/config.py2 b/examples/MultiblockJetCoflow/config.py2 new file mode 100644 index 00000000..1a690bdd --- /dev/null +++ b/examples/MultiblockJetCoflow/config.py2 @@ -0,0 +1,596 @@ +#!/usr/bin/env python +import os.path +import numpy as np +from scipy.optimize import fsolve +import numpy.random as random + +import plot3dnasa as p3d + +EPSILON = np.finfo(float).eps + +class InstabilityMode: + + def __init__(self, n=0, omega=0., theta=1., M1=0., M2=0., + r_nozzle=0.5, gamma=1.4): + self.n = n + self.omega = omega + self.theta = theta + self.M1 = M1 + self.M2 = M2 + self.r_nozzle = r_nozzle + self.gamma = gamma + + def set_domain(self, r, r_lower, r_match, r_upper): + self._r = r + i_lower = np.argmin(np.abs(self._r - r_lower)) + i_match = np.argmin(np.abs(self._r - r_match)) + i_upper = np.argmin(np.abs(self._r - r_upper)) + self._num_steps_inner = i_match - i_lower + self._num_steps_outer = i_upper - i_match + self._r_lower = self._r[i_lower] + self._r_match = self._r[i_match] + self._r_upper = self._r[i_upper] + return self + + def update(self): + self.T1 = 1. / (1. + 0.5 * (self.gamma - 1.) * + self.M1 ** 2) / (self.gamma - 1.) + self.T2 = 1. / (self.gamma - 1.) + self.U1 = self.M1 * np.sqrt((self.gamma - 1.) * self.T1) + self.U2 = self.M2 * np.sqrt((self.gamma - 1.) * self.T2) + return self + + def mean_flow(self, r): + u = 0.5 * (1. + np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle))) + u_dot = -0.125 / self.theta * (1. - np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle)) ** 2) * ( + self.r_nozzle / (r + EPSILON) ** 2 + 1. / self.r_nozzle) + # u, \rho, a, du/dr, d\rho/dr + mean_flow = np.array([np.empty_like(r) for i in range(5)]) + mean_flow[0] = (self.U1 - self.U2) * u + mean_flow[1] = 1. / (self.gamma - 1.) / (( + self.T1 * (mean_flow[0] - self.U2) + self.T2 * ( + self.U1 - mean_flow[0])) / (self.U1 - self.U2) + 0.5 * ( + mean_flow[0] - self.U2) * (self.U1 - mean_flow[0])) + mean_flow[2] = np.sqrt(1. / mean_flow[1]) + mean_flow[3] = (self.U1 - self.U2) * u_dot + mean_flow[4] = -(self.gamma - 1.) * mean_flow[1] ** 2 * (( + self.T1 - self.T2) / (self.U1 - self.U2) + 0.5 * ( + self.U1 + self.U2) - mean_flow[0]) * mean_flow[3] + return mean_flow + + def rayleigh_rhs(self, r, p_hat, alpha): + u, rho, a, u_r, rho_r = self.mean_flow(r) + return np.array([p_hat[1], + - (1. / r - rho_r / rho + 2. * alpha / + (self.omega - alpha * u) * u_r) * p_hat[1] - + ((self.omega - alpha * u) ** 2 / a ** 2 - + self.n ** 2 / r ** 2 - alpha ** 2) * p_hat[0]]) + + def inner_solution(self, r, alpha): + import scipy.special + eta = np.sqrt((self.omega - alpha * (self.U1 - self.U2)) ** 2 / + (self.gamma - 1.) * self.T1 - alpha ** 2) + return np.array([scipy.special.jn(self.n, eta * r), + eta * 0.5 * (scipy.special.jn(self.n - 1, eta * r) - + scipy.special.jn(self.n + 1, eta * r))]) + + def outer_solution(self, r, alpha): + import scipy.special + eta = np.sqrt(self.omega ** 2 - alpha ** 2) + return np.array([scipy.special.hankel1(self.n, + np.sign(eta.imag) * eta * r), + np.sign(eta.imag) * eta * 0.5 * ( + scipy.special.hankel1(self.n - 1, + np.sign(eta.imag) * + eta * r) - + scipy.special.hankel1(self.n + 1, + np.sign(eta.imag) * + eta * r))]) + + def newton_raphson_func(self, alpha): + from scipy.integrate import ode + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(alpha) + # Inner solution + integrator.set_initial_value(self.inner_solution(self._r_lower, alpha), + self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + integrator.integrate(integrator.t + dr) + inner_solution = integrator.y + # Outer solution + integrator.set_initial_value(self.outer_solution(self._r_upper, alpha), + self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + integrator.integrate(integrator.t - dr) + outer_solution = integrator.y + if abs(outer_solution[0] / inner_solution[0]) < 1e-6: + return inner_solution[1] - outer_solution[1] * \ + inner_solution[0] / outer_solution[0] + return inner_solution[1] * outer_solution[0] / inner_solution[0] - \ + outer_solution[1] + + def find_eigenvalue(self, initial_guess, max_iterations=200, + tolerance=1e-10): + x = initial_guess + y = self.newton_raphson_func(x) + it = 1 + while abs(y) > tolerance and it <= max_iterations: # Newton-Raphson + dx = random.uniform(1e-10, 1e-8) + 1j * \ + random.uniform(1e-10, 1e-8) # step size for derivative + x = x - dx * y / (self.newton_raphson_func(x + dx) - y) + y = self.newton_raphson_func(x) + it = it + 1 + if it >= max_iterations: + print "Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y) + self.alpha = x.real - 1.j * abs(x.imag) + return self + + def find_eigenfunction(self, tolerance=1e-8): + from scipy.integrate import ode + from scipy.interpolate import interp1d + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(self.alpha) + p_hat = np.array([np.empty_like(self._r) for i in range(2)], + dtype='complex128') + i_lower = np.argmin(np.abs(self._r - self._r_lower)) + p_hat[:,:i_lower] = self.inner_solution(self._r[:i_lower], self.alpha) + i = i_lower + integrator.set_initial_value(self.inner_solution( + self._r_lower, self.alpha), self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t + dr) + i += 1 + p_hat[:,i] = integrator.y + i_upper = np.argmin(np.abs(self._r - self._r_upper)) + p_hat[:,i_upper:] = self.outer_solution(self._r[i_upper:], self.alpha) + i = i_upper + integrator.set_initial_value(self.outer_solution( + self._r_upper, self.alpha), self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t - dr) + i -= 1 + outer_solution = integrator.y + scaling_factor = integrator.y[0] / p_hat[0,i] + scaling_factor_inverse = 1. / scaling_factor + if abs(scaling_factor) < 1e-6: + p_hat[:,i+1:] *= scaling_factor_inverse + else: + p_hat[:,:i+1] *= scaling_factor + assert abs(p_hat[1,i] - integrator.y[1]) < tolerance + self.p_hat_dot = interp1d(self._r, p_hat[1,:], kind='linear') + self.p_hat = interp1d(self._r, p_hat[0,:], kind='linear') + return self + + def get_eigenmode(self, r): + u, rho, a, u_r, rho_r = self.mean_flow(r) + p_hat = self.p_hat(r) + p_hat_r = self.p_hat_dot(r) + omega = self.omega - self.alpha * u + u_hat_r = 1. / (1.j * rho * omega) * p_hat_r + u_hat_x = self.alpha * p_hat / (rho * omega) + \ + u_hat_r / (1.j * omega) * u_r + rho_hat = p_hat / a ** 2 + u_hat_r / (1.j * omega) * rho_r + return np.array([rho_hat, + rho * u_hat_r, + self.n * p_hat / (r * omega + EPSILON), + rho_hat * u + rho * u_hat_x, + p_hat / (self.gamma - 1.) + 0.5 * rho_hat * u ** 2 + + rho * u * u_hat_x]) + +def mesh_segment(n, x_min, x_max, dx_min, dx_max=None): + """ If dx_max is None, returns a one-sided stretched mesh from x_min + to x_max with minimum spacing dx_min at x_min. Otherwise, returns a + two-sided stretched mesh with spacing dx_min and dx_max at x_min and + x_max, respectively. + """ + from scipy.optimize import curve_fit + if dx_max is None: + f = lambda x, sigma: np.sinh(sigma * x) / np.sinh(sigma) + sigma = fsolve(lambda x: ((x_max - x_min) * f(1. / (n - 1.), x) - + dx_min) ** 2, 2.) + return x_min + (x_max - x_min) * f(np.linspace(0., 1., n), sigma) + f = lambda xi, a, b, c, d: a + b * np.tanh(c * (xi - d)) + a, b, c, d = curve_fit(f, np.array([0., 1. / (n - 1), 1. - + 1. / (n - 1), 1.]), + np.array([x_min, x_min + dx_min, + x_max - dx_max, x_max]))[0] + return f(np.linspace(0., 1., n), a, b, c, d) + +def axial_coordinate(z_min=-9., z_max=34., z_physical=24., num_axial=512, + num_inflow_sponge=48, num_outflow_sponge=28, + num_potential_core=240, potential_core_length=8., + dz_exit=0.04, dz_min=0.01, dz_physical_outflow=0.22): + z = -mesh_segment(num_inflow_sponge + 1, 0., -z_min, dz_exit)[::-1] + z = np.append(z[:-1], mesh_segment(num_potential_core + 1, 0., + potential_core_length, dz_exit, dz_min)) + z = np.append(z[:-1], mesh_segment( + num_axial - (num_inflow_sponge + num_outflow_sponge + + num_potential_core), potential_core_length, z_physical, + dz_min, dz_physical_outflow)) + z = np.append(z[:-1], mesh_segment(num_outflow_sponge + 1, z_physical, + z_max, dz_physical_outflow)) + return z + +def dc_func(x, n, num_const_dr, dr_min, a_inner, sigma): + s = np.linspace(0., 1., n) + dc = np.empty_like(s) + dc[:num_const_dr] = x * (0.5 - 0.5 * a_inner) / (n + 1) + dc[-num_const_dr:] = dr_min + y = -np.tanh((s[num_const_dr:-num_const_dr] - 0.5) / sigma) + dc[num_const_dr:-num_const_dr] = dc[-1] + (dc[0] - dc[-1]) * \ + (y - y.min()) / (y.max() - y.min()) + c = np.cumsum(dc) + 0.5 * a_inner - dc[0] + return (c[-1] - 0.5) ** 2 + +def nozzle_quadrant(grid_size, num_const_dr=4, a_inner=0.24, + p_inner=1.12, dr_min=0.005): + theta = np.linspace(0., np.pi / 2, grid_size[1]) + s = np.linspace(0., 1., grid_size[0]) + p = np.empty_like(s) + p[:num_const_dr] = p_inner + p[-num_const_dr:] = 2. + p[num_const_dr:-num_const_dr] = np.linspace(p_inner, 2., grid_size[0] - + 2 * num_const_dr) + sigma = 0.2 + xi = fsolve(dc_func, 1.2, args=(grid_size[0], num_const_dr, + dr_min, a_inner, sigma)) + dc = np.empty_like(s) + dc[:num_const_dr] = xi * (0.5 - 0.5 * a_inner) / (grid_size[0] + 1) + dc[-num_const_dr:] = dr_min + y = -np.tanh((s[num_const_dr:-num_const_dr] - 0.5) / sigma) + dc[num_const_dr:-num_const_dr] = dc[-1] + (dc[0] - dc[-1]) * \ + (y - y.min()) / (y.max() - y.min()) + c = np.cumsum(dc) + 0.5 * a_inner - dc[0] + x = np.zeros([grid_size[0], grid_size[1]]) + y = np.zeros_like(x) + for i in range(grid_size[0]): + r = c[i] / (np.cos(theta) ** p[i] + + np.sin(theta) ** p[i]) ** (1. / p[i]) + x[i,:] = r * np.cos(theta) + y[i,:] = r * np.sin(theta) + return x, y + +def near_field_quadrant(grid_size, num_const_dr=4, dr_min=0.005, r_max=12.5): + r = np.append(np.linspace( + 0.5, 0.5 + (num_const_dr - 1) * dr_min, num_const_dr), mesh_segment( + grid_size[0] - num_const_dr + 2, 0.5 + (num_const_dr - 1) * dr_min, + r_max, dr_min)[1:]) + p3d.mesh_stats(r) + r, theta = np.meshgrid(r[1:], np.linspace(0., np.pi / 2, grid_size[1])) + x = r * np.cos(theta) + y = r * np.sin(theta) + return x.T, y.T + +def complete_rotated_blocks(g): + n = g.get_size(0)[2] + for i in range(2, 5): + for k in range(n): + g.xyz[i][:,:,k,0] = -g.xyz[i-1][:,:,k,1] + g.xyz[i][:,:,k,1] = g.xyz[i-1][:,:,k,0] + g.xyz[i][:,:,:,2] = g.xyz[i-1][:,:,:,2] + return g + +def elliptic_solve(x, tol=1e-4, max_iter=2000): + y = np.zeros_like(x) + i = 0 + while np.amax(np.abs(x - y)) > tol and i < max_iter: + y[:,:] = x + x[1:-1,1:-1] = (4. * x[1:-1,1:-1] + x[:-2,1:-1] + x[2:,1:-1] + + x[1:-1,:-2] + x[1:-1,2:]) / 8. + i += 1 + return x + +def complete_inner_block(g, smoothing_tol=1e-8): + from scipy.ndimage.filters import uniform_filter + n = g.get_size(0) + g.xyz[0][0,:,0,0:2] = g.xyz[2][0,::-1,0,0:2] + g.xyz[0][-1,:,0,0:2] = g.xyz[4][0,:,0,0:2] + g.xyz[0][:,0,0,0:2] = g.xyz[3][0,:,0,0:2] + g.xyz[0][:,-1,0,0:2] = g.xyz[1][0,::-1,0,0:2] + for i in range(1, n[0] - 1): + for j in range(1, n[1] - 1): + g.xyz[0][i,j,0,0] = g.xyz[0][0,j,0,0] + i / (n[0] - 1.) * \ + (g.xyz[0][-1,j,0,0] - g.xyz[0][0,j,0,0]) + g.xyz[0][i,j,0,1] = g.xyz[0][i,0,0,1] + j / (n[1] - 1.) * \ + (g.xyz[0][i,-1,0,1] - g.xyz[0][i,0,0,1]) + g.xyz[0][:,:,0,0] = elliptic_solve(g.xyz[0][:,:,0,0], tol=smoothing_tol) + g.xyz[0][:,:,0,1] = elliptic_solve(g.xyz[0][:,:,0,1], tol=smoothing_tol) + for k in range(n[2]): + g.xyz[0][:,:,k,0:2] = g.xyz[0][:,:,0,0:2] + g.xyz[0][:,:,k,2] = g.xyz[1][0,0,k,2] + return g + +def plot_axial_spacing(z): + import matplotlib.pyplot as plt + ax = plt.subplot(111) + dz = z[1:] - z[:-1] + ax.plot(z[:-1], dz, 'ko-') + plt.show() + +def plot_radial_spacing(r): + import matplotlib.pyplot as plt + ax = plt.subplot(111) + dr = r[1:] - r[:-1] + ax.plot(r[:-1], dr, 'ko-') + plt.show() + +def plot_jacobian_continuity(g): + import matplotlib.pyplot as plt + from numpy.linalg import det + ax = plt.subplot(111) + f = p3d.compute_jacobian(g) + for k in range(5): + x = g.xyz[k][:,:,0,0] + y = g.xyz[k][:,:,0,1] + z = np.empty_like(x) + for i in range(z.shape[0]): + for j in range(z.shape[1]): + z[i,j] = 1. / det(np.reshape(f.f[k][i,j,0,:], [3, 3])) + if k == 0: + vmin = z.min() + vmax = z.max() + c = ax.contour(x, y, z, levels=np.linspace(vmin, vmax, 31)) + plt.colorbar(c) + ax.set_xlim([-0.5, 0.5]) + ax.set_ylim([-0.5, 0.5]) + ax.set_aspect('equal') + plt.show() + +def grid(num_radial_nozzle, num_radial_near_field, num_azimuthal, + num_axial=512, a_inner=0.24, p_inner=1.12, dr_min=0.005): + assert num_azimuthal % 4 == 0 + num_radial = num_radial_nozzle + num_radial_near_field + g = p3d.Grid().set_size([ + [num_azimuthal / 4, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial], + [num_radial, num_azimuthal / 4, num_axial]], True) + x, y = nozzle_quadrant([num_radial_nozzle, num_azimuthal / 4], + a_inner=a_inner, p_inner=p_inner, dr_min=dr_min) + for k in range(num_axial): + g.xyz[1][:num_radial_nozzle,:,k,0] = x + g.xyz[1][:num_radial_nozzle,:,k,1] = y + x, y = near_field_quadrant([num_radial_near_field, num_azimuthal / 4], + dr_min=dr_min) + for k in range(num_axial): + g.xyz[1][num_radial_nozzle:,:,k,0] = x + g.xyz[1][num_radial_nozzle:,:,k,1] = y + if num_axial > 1: + z = axial_coordinate(num_axial=num_axial) + p3d.mesh_stats(z) + # plot_axial_spacing(z) + for k in range(num_axial): + g.xyz[1][:,:,k,2] = z[k] + complete_rotated_blocks(g) + for i in range(1, 5): + x = np.copy(g.xyz[i][:,:,:,0]) + g.xyz[i][:,:,:,0] = (g.xyz[i][:,:,:,0] - + g.xyz[i][:,:,:,1]) / np.sqrt(2.) + g.xyz[i][:,:,:,1] = (x + g.xyz[i][:,:,:,1]) / np.sqrt(2.) + complete_inner_block(g) + r = np.append(g.xyz[0][:,num_azimuthal/8,0,0], + g.xyz[4][1:,num_azimuthal/8,0,0]) + # plot_radial_spacing(r) + # plot_jacobian_continuity(g) + return g + +def target_state(g, M1=1.5, M2=0.2, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + T1 = 1. / (1. + 0.5 * (gamma - 1.) * M1 ** 2) / (gamma - 1.) + T2 = 1. / (gamma - 1.) + U1 = M1 * np.sqrt((gamma - 1.) * T1) + U2 = M2 * np.sqrt((gamma - 1.) * T2) + for i, xyz in enumerate(g.xyz): + z = xyz[0,0,:,2] + r = np.sqrt(xyz[:,:,0,0] ** 2 + xyz[:,:,0,1] ** 2) + condlist = [z <= 0., np.logical_and(z > 0., z < 24.), z >= 24.] + r0 = np.select(condlist, [0.5 + np.zeros_like(z), 0.04125 * z + 0.5, + 0.075 * z - 0.31]) + theta = np.select(condlist, [0.04 + np.zeros_like(z), + 0.46 * z / 24. + 0.04, 0.5]) + U_j = np.where(z <= 2.65, U1 + np.zeros_like(z), + (U1 - U2) * np.exp(-(z - 2.65) / 25.) + U2) + T_j = np.where(z <= 0., T1 + np.zeros_like(z), + T2 / (1. + (T2 - T1) / T1 * np.exp(-0.078 * z))) + for k in range(z.size): + s.q[i][:,:,k,3] = 0.5 * (U_j[k] - U2) * (1. + np.tanh( + 0.25 / theta[k] * (r0[k] / r - r / r0[k]))) + U2 + s.q[i][:,:,k,0] = 1. / (gamma - 1.) / ((T_j[k] * ( + s.q[i][:,:,k,3] - U2) + T2 * (U_j[k] - s.q[i][:,:,k,3])) / ( + U_j[k] - U2) + 0.5 * (s.q[i][:,:,k,3] - U2) * ( + U_j[k] - s.q[i][:,:,k,3])) + return s.fromprimitive(gamma) + +def plot_eigenvalues(St, alpha, u_j, theta_j): + import matplotlib.pyplot as plt + ax = plt.subplot(121) + for i in range(alpha.shape[0]): + ax.plot(St, -alpha[i,:].imag * theta_j, 'rs-', mec='r', mfc='w') + ax.set_xlim([0.35, 0.95]) + ax.set_ylim([0.05, 0.11]) + ax = plt.subplot(122) + omega = 2. * np.pi * u_j * St + for i in range(alpha.shape[0]): + ax.plot(St, omega / alpha[i,:].real / u_j, 'rs-', mec='r', mfc='w') + ax.set_xlim([0.35, 0.95]) + ax.set_ylim([0.5, 0.75]) + plt.show() + +def eigenmodes(M1=1.5, M2=0.2, theta_j=0.04, show_progress=True): + u_j = InstabilityMode(M1=1.5, M2=0.2, + theta=theta_j).update().mean_flow(EPSILON)[0] + n = np.arange(1, 6) + St = np.array([0.43, 0.51, 0.61, 0.69, 0.74, 0.88]) + alpha = np.empty([n.size, St.size], dtype='complex128') + r_lower = 0.025 + r_match = 0.25 + r_upper = 3. + r = np.linspace(0., r_lower, 5001) + r = np.append(r[:-1], np.linspace(r_lower, r_match, 5001)) + r = np.append(r[:-1], np.linspace(r_match, r_upper, 5001)) + r = np.append(r[:-1], np.linspace(r_upper, 15., 5001)) + # Initialize eigenmodes. + initial_guess = 1. - 1.j + modes = [[InstabilityMode() for n_ in n] for St_ in St] + if show_progress: + from progressbar import ProgressBar, Percentage, Bar, ETA + print 'Computing eigenmodes:' + p = ProgressBar(widgets = [Percentage(), ' ', + Bar('=', left = '[', right = ']'), ' ', + ETA()], maxval = alpha.size).start() + for j, St_ in enumerate(St): + guess = initial_guess + for i, n_ in enumerate(n): + modes[j][i] = InstabilityMode( + M1=1.5, M2=0.2, theta=theta_j, n=n_, + omega=2. * np.pi * u_j * St_).update().set_domain( + r, r_lower, r_match, r_upper) + modes[j][i].find_eigenvalue(guess).find_eigenfunction() + guess = alpha[i,j] = modes[j][i].alpha + if i == 0: + initial_guess = modes[j][i].alpha + if show_progress: + p.update(i + n.size * j) + if show_progress: + p.finish() + # plot_eigenvalues(St, alpha, u_j, theta_j) + return modes + +def extract_inflow(g, num_inflow_sponge=49): + n = g.get_size() + n[:,2] = num_inflow_sponge + gi = p3d.Grid().set_size(n, True) + for i, xyz in enumerate(g.xyz): + gi.xyz[i] = xyz[:,:,:num_inflow_sponge,:] + return gi + +def inflow_perturbations(g, modes): + phi_p = 2. * np.pi * random.rand(len(modes)) + phi_n = 2. * np.pi * random.rand(len(modes)) + sr = p3d.Solution().copy_from(g) + si = p3d.Solution().copy_from(g) + sr._format.aux_header[1] = si._format.aux_header[1] = modes[0].omega + for i in range(g.nblocks): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + theta = np.arctan2(g.xyz[i][:,:,0,1], g.xyz[i][:,:,0,0]) + z = g.xyz[i][0,0,:,2] + si.q[i].fill(0.) + sr.q[i].fill(0.) + for j, mode in enumerate(modes): + q = mode.get_eigenmode(r) + n = mode.n + for l in range(q.shape[0]): + if l == 2: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) - \ + np.exp(-1.j * n * theta + phi_n[j]) + else: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) + \ + np.exp(-1.j * n * theta + phi_n[j]) + u = q[1] * np.cos(theta) - q[2] * np.sin(theta) + v = q[1] * np.sin(theta) + q[2] * np.cos(theta) + q[1] = u + q[2] = v + for l in range(q.shape[0]): + for k, z_ in enumerate(z): + sr.q[i][:,:,k,l] += np.real( + q[l] * np.exp(1.j * mode.alpha * z_)) + si.q[i][:,:,k,l] += np.imag( + q[l] * np.exp(1.j * mode.alpha * z_)) + return sr, si + +def target_mollifier(g): + z_min = 0. + z_max = 24. + r_min = 7. + r_max = 9. + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.tanh_support(z, z_min, z_max, 40., 0.2) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion.' + block_code[i], 'COST_TARGET', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +def control_mollifier(g): + z_min = 1. + z_max = 3. + r_min = 0.3 + r_max = 0.7 + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.tanh_support(z, z_min, z_max, 16., 0.2) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.tanh_support(r[:,k], r_min, r_max, 20., 0.2) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin = min(np.where(r[:,i] >= r_min)[0][0] + for i in range(n[i][1])) + imax = max(np.where(r[:,i] <= r_max)[0][-1] + 2 + for i in range(n[i][1])) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion.' + block_code[i], 'ACTUATOR', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +def axisymmetric_grid(num_axial=512, r_max=12.5): + z = axial_coordinate(num_axial=num_axial) + r = np.linspace(0., r_max, 1001) + x, y = np.meshgrid(z, r) + g = p3d.Grid().set_size([r.size, 1, z.size], True) + g.xyz[0][:,0,:,0] = y + g.xyz[0][:,0,:,2] = x + return g + +if __name__ == '__main__': + filename = 'MultiblockJetCoflow.xyz' + if not os.path.isfile(filename): + g = grid(60, 196, 132, a_inner=0.24, p_inner=1.08634735266) + g.save(filename) + g = p3d.fromfile(filename) + target_state(g).save('MultiblockJetCoflow.target.q') + gi = extract_inflow(g) + gi.save('MultiblockJetCoflow.inflow.xyz') + modes = eigenmodes() + for i, mode in enumerate(modes): + sr, si = inflow_perturbations(gi, mode) + sr.save('MultiblockJetCoflow-%02d.eigenmode_real.q' % (i + 1)) + si.save('MultiblockJetCoflow-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/MultiblockOneDWave/config.py b/examples/MultiblockOneDWave/config.py index a13e673e..baf9f723 100644 --- a/examples/MultiblockOneDWave/config.py +++ b/examples/MultiblockOneDWave/config.py @@ -67,8 +67,8 @@ def target_mollifier(g): else: imin, imax = p3d.find_extents(x, 0., x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -96,8 +96,8 @@ def control_mollifier(g): else: imin, imax = p3d.find_extents(x, 0., x_max) jmin, jmax = p3d.find_extents(y, y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/MultiblockOneDWave/config.py2 b/examples/MultiblockOneDWave/config.py2 new file mode 100644 index 00000000..a13e673e --- /dev/null +++ b/examples/MultiblockOneDWave/config.py2 @@ -0,0 +1,125 @@ +#!/usr/bin/env python +import numpy as np +from scipy.optimize import fsolve +import numpy.random as random + +import plot3dnasa as p3d + +EPSILON = np.finfo(float).eps + +def grid(numX,numY,flip=True): + x_min = -14. + x_max = 14. + y_min = -14. + y_max = 14. + size = [[numX,numY],[numX,numY]] + g = p3d.Grid().set_size(size,True) + if (flip): + x1 = np.linspace(0., x_min, g.size[0,0]) + else: + x1 = np.linspace(x_min, 0., g.size[0,0]) + x2 = np.linspace(0., x_max, g.size[1,0]) + + hy = (y_max-y_min)/numY + y = np.linspace(y_min+0.5*hy, y_max-0.5*hy, g.size[0,1]) + g.xyz[0][:,:,0,2] = 0. + g.xyz[1][:,:,0,2] = 0. + if (flip): + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x1, -y)) + else: + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x1, y)) + g.xyz[1][:,:,0,:2] = np.transpose(np.meshgrid(x2, y)) + return g + +def initial_condition(g, mach_number=1.3, gamma=1.4): + x0, sigma = -7.0, 1.0 + from math import atan + pi = atan(1.0)*4.0 + x = g.xyz[0][:,0,0,0] + + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i in range(np.size(g.xyz[0],1)): + s.q[0][:,i,0,1] += 1.0/np.sqrt(2.0*pi)/sigma*np.exp( -(x-x0)**2/2.0/sigma/sigma ) + return s.fromprimitive(gamma) + +def target_mollifier(g): + x_min = -1. + x_max = 1. + y_min = -10. + y_max = 10. + f = p3d.Function().copy_from(g) + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + y = g.xyz[i][0,:,0,1] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.tanh_support(y, y_min, y_max, 5., 0.2) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + if i==0: + imin, imax = p3d.find_extents(-x, 0., -x_min) + jmin, jmax = p3d.find_extents(-y, y_min, y_max) + else: + imin, imax = p3d.find_extents(x, 0., x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion'+block_code[i], 'COST_TARGET', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 5. + y_min = -2. + y_max = 2. + f = p3d.Function().copy_from(g) + n = f.get_size() + block_code = ['E','W'] + for i, fi in enumerate(f.f): + x = g.xyz[i][:,0,0,0] + y = g.xyz[i][0,:,0,1] + if x.max() < x_min or x.min() > x_max: + fi.fill(0.) + continue + fi.fill(1.) + for j in range(n[i][0]): + fi[j,:,0,0] *= p3d.cubic_bspline_support(y, y_min, y_max) + for k in range(n[i][1]): + fi[:,k,0,0] *= p3d.cubic_bspline_support(x, x_min, x_max,strict=False) + if i==0: + imin, imax = p3d.find_extents(-x, 0., -x_min) + jmin, jmax = p3d.find_extents(-y, y_min, y_max) + else: + imin, imax = p3d.find_extents(x, 0., x_max) + jmin, jmax = p3d.find_extents(y, y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion'+block_code[i], 'ACTUATOR', i+1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + for i, fi in enumerate(f.f): + fi[:,:,:,0] = s.toprimitive().q[i][:,:,:,4] + return f + + +if __name__ == '__main__': + g = grid(101,11,True) + output_prefix = 'MultiblockOneDimensionWave' + g.save(output_prefix + '.xyz') + initial_condition(g).save(output_prefix + '.ic.q') + control_mollifier(g).save(output_prefix + '.control_mollifier.f') + target_mollifier(g).save(output_prefix + '.target_mollifier.f') +# target_state(g).save('MultiblockJet.target.q') +# initial_condition(g).save('MultiblockJet.ic.q') +# gi = extract_inflow(g) +# gi.save('MultiblockJet.inflow.xyz') +# modes = eigenmodes() +# for i, mode in enumerate(modes): +# sr, si = inflow_perturbations(gi, mode) +# sr.save('MultiblockJet-%02d.eigenmode_real.q' % (i + 1)) +# si.save('MultiblockJet-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/NACA0012/config.py b/examples/NACA0012/config.py index 1e565ac5..da552142 100644 --- a/examples/NACA0012/config.py +++ b/examples/NACA0012/config.py @@ -29,83 +29,83 @@ def write_glyph_file(filename, grid_size, t=0.12, alpha=2., ds_te=0.0001, x_start = 0.52 * c # Write glyph file. with open(filename, 'w') as f: - print >>f, """ + print(""" gg::memClear gg::defReset gg::tolReset gg::dispViewReset - """ - print >>f, 'gg::dbCurveBegin -type CUBIC' + """, file=f) + print('gg::dbCurveBegin -type CUBIC', file=f) for x, y in zip(x_airfoil[1:], y_airfoil[1:]): - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, y, 0.) - print >>f, 'set db_NACA1 [gg::dbCurveEnd]' - print >>f, 'gg::dbCurveBegin -type CUBIC' + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, y, 0.), file=f) + print('set db_NACA1 [gg::dbCurveEnd]', file=f) + print('gg::dbCurveBegin -type CUBIC', file=f) for x, y in zip(reversed(x_airfoil[1:]), reversed(y_airfoil[1:])): - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, -y, 0.) - print >>f, 'set db_NACA2 [gg::dbCurveEnd]' - print >>f, 'gg::dbCurveBegin -type CONIC -rho 0.5' - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (x_airfoil[1], y_airfoil[1], 0.) - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (x_airfoil[1], -y_airfoil[1], 0.) - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' \ - % (x_airfoil[0], y_airfoil[0], 0.) - print >>f, 'set db_NACA3 [gg::dbCurveEnd]' - print >>f, 'gg::dbCurveBegin -type CONIC -rho 0.5' - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (x_airfoil[-1], y_airfoil[-1], 0.) - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (x_airfoil[-1], -y_airfoil[-1], 0.) - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (x_te, 0., 0.) - print >>f, 'set db_NACA4 [gg::dbCurveEnd]' - print >>f, """ + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, -y, 0.), file=f) + print('set db_NACA2 [gg::dbCurveEnd]', file=f) + print('gg::dbCurveBegin -type CONIC -rho 0.5', file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[1], y_airfoil[1], 0.), file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[1], -y_airfoil[1], 0.), file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' \ + % (x_airfoil[0], y_airfoil[0], 0.), file=f) + print('set db_NACA3 [gg::dbCurveEnd]', file=f) + print('gg::dbCurveBegin -type CONIC -rho 0.5', file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[-1], y_airfoil[-1], 0.), file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[-1], -y_airfoil[-1], 0.), file=f) + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_te, 0., 0.), file=f) + print('set db_NACA4 [gg::dbCurveEnd]', file=f) + print(""" set con_NACA1 [gg::conOnDBEnt $db_NACA1] set con_NACA2 [gg::conOnDBEnt $db_NACA2] set con_NACA3 [gg::conOnDBEnt $db_NACA3] set con_NACA4 [gg::conOnDBEnt $db_NACA4] - """ - print >>f, 'set con_NACA5 [gg::conSplit $con_NACA1 ' \ - '[gg::conGetPt $con_NACA1 -x %f]]' % (x_start) - print >>f, """ + """, file=f) + print('set con_NACA5 [gg::conSplit $con_NACA1 ' \ + '[gg::conGetPt $con_NACA1 -x %f]]' % (x_start), file=f) + print(""" set con_NACA6 [gg::conJoin $con_NACA5 $con_NACA4] set con_NACA7 [gg::conJoin $con_NACA6 $con_NACA2] set con_NACA8 [gg::conJoin $con_NACA7 $con_NACA3] set con_NACA [gg::conJoin $con_NACA1 $con_NACA8] - """ - print >>f, 'gg::conDim $con_NACA %i' % (grid_size[0]) - print >>f, 'set LE_pt [gg::conGetPt $con_NACA -x 0]' - print >>f, 'gg::conSetBreakPt $con_NACA $LE_pt' - print >>f, 'set TE_pt [gg::conGetPt $con_NACA -y 0]' - print >>f, 'gg::conSetBreakPt $con_NACA $TE_pt' - print >>f, 'gg::conBreakPtSpacing $con_NACA -breakpt 1 %f' % \ - (ds_te * c) - print >>f, 'gg::conBreakPtSpacing $con_NACA -breakpt 2 %f' % \ - (ds_le * c) - print >>f, 'set ds_start [ggu::vec3Length [ggu::vec3Sub [' \ + """, file=f) + print('gg::conDim $con_NACA %i' % (grid_size[0]), file=f) + print('set LE_pt [gg::conGetPt $con_NACA -x 0]', file=f) + print('gg::conSetBreakPt $con_NACA $LE_pt', file=f) + print('set TE_pt [gg::conGetPt $con_NACA -y 0]', file=f) + print('gg::conSetBreakPt $con_NACA $TE_pt', file=f) + print('gg::conBreakPtSpacing $con_NACA -breakpt 1 %f' % \ + (ds_te * c), file=f) + print('gg::conBreakPtSpacing $con_NACA -breakpt 2 %f' % \ + (ds_le * c), file=f) + print('set ds_start [ggu::vec3Length [ggu::vec3Sub [' \ 'gg::conGetPt $con_NACA %i] [gg::conGetPt $con_NACA %i]]]' % \ - (grid_size[0], grid_size[0] - 1) - print >>f, 'gg::conBeginSpacing $con_NACA -sub 1 $ds_start' - print >>f, 'gg::conEndSpacing $con_NACA -sub 3 $ds_start' - print >>f, 'gg::domExtrusionBegin [list $con_NACA] -edge' - print >>f, 'gg::domExtrusionMode HYPERBOLIC' - print >>f, 'gg::domExtrusionAtt -s_init %f -march_plane {0 0 1} ' \ + (grid_size[0], grid_size[0] - 1), file=f) + print('gg::conBeginSpacing $con_NACA -sub 1 $ds_start', file=f) + print('gg::conEndSpacing $con_NACA -sub 3 $ds_start', file=f) + print('gg::domExtrusionBegin [list $con_NACA] -edge', file=f) + print('gg::domExtrusionMode HYPERBOLIC', file=f) + print('gg::domExtrusionAtt -s_init %f -march_plane {0 0 1} ' \ '-stop_height %f -growth_geometric %f -normal_count 20 ' \ '-normal_relax 1 -vol_smoothing 0.25' % \ - (ds_normal * c, stop_height * c, stretch_ratio) - print >>f, 'gg::domExtrusionStep -result ExtResult %i' % \ - (grid_size[1] - 1) - print >>f, 'set dom_NACA [gg::domExtrusionEnd]' - print >>f, 'gg::domTransformBegin $dom_NACA -maintain_linkage' - print >>f, 'gg::xformRotate [list 0 0 0] [list 0 0 1] %f' % (-alpha) - print >>f, 'gg::domTransformEnd' - print >>f, 'gg::domTransformBegin $dom_NACA -maintain_linkage' - print >>f, 'gg::xformScale [list 0 0 0] [list %f %f %f]' % \ - (1. / x_te, 1. / x_te, 1. / x_te) - print >>f, 'gg::domTransformEnd' - print >>f, 'gg::dbDelete ALL' - print >>f, 'gg::domExport $dom_NACA \"NACA0012.xyz\" -style PLOT3D ' \ - '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + (ds_normal * c, stop_height * c, stretch_ratio), file=f) + print('gg::domExtrusionStep -result ExtResult %i' % \ + (grid_size[1] - 1), file=f) + print('set dom_NACA [gg::domExtrusionEnd]', file=f) + print('gg::domTransformBegin $dom_NACA -maintain_linkage', file=f) + print('gg::xformRotate [list 0 0 0] [list 0 0 1] %f' % (-alpha), file=f) + print('gg::domTransformEnd', file=f) + print('gg::domTransformBegin $dom_NACA -maintain_linkage', file=f) + print('gg::xformScale [list 0 0 0] [list %f %f %f]' % \ + (1. / x_te, 1. / x_te, 1. / x_te), file=f) + print('gg::domTransformEnd', file=f) + print('gg::dbDelete ALL', file=f) + print('gg::domExport $dom_NACA \"NACA0012.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE', file=f) def grid(**kwargs): if not os.path.isfile('NACA0012.xyz'): diff --git a/examples/NACA0012/config.py2 b/examples/NACA0012/config.py2 new file mode 100644 index 00000000..1e565ac5 --- /dev/null +++ b/examples/NACA0012/config.py2 @@ -0,0 +1,125 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d +import tempfile +import subprocess +import os +import os.path + +def airfoil_profile(x, c, t): + return 5. * t * c * (0.2969 * np.sqrt(x / c) - 0.1260 * (x / c) - + 0.3516 * (x / c) ** 2 + 0.2843 * (x / c) ** 3 - + 0.1015 * (x / c) ** 4) + +def airfoil_slope(x, c, t): + return 5. * t * (0.14845 / np.sqrt(x / c) - 0.1260 - 0.7032 * (x / c) + + 0.8529 * (x / c) ** 2 - 0.406 * (x / c) ** 3) + +def write_glyph_file(filename, grid_size, t=0.12, alpha=2., ds_te=0.0001, + ds_le=0.0008, ds_normal=0.00025, stretch_ratio=1.02, + stop_height=100.): + c = 2000. + s = np.linspace(0., 1., 200) + x_airfoil = np.cumsum(np.tanh(3.5 * (1. - s)) + np.tanh(3.5 * s) - 1.) + x_airfoil = c * (x_airfoil - x_airfoil.min()) / \ + (x_airfoil.max() - x_airfoil.min()) + y_airfoil = airfoil_profile(x_airfoil, c, t) + x_te = x_airfoil[-1] - 0.5 * y_airfoil[-1] / \ + airfoil_slope(x_airfoil[-1], c, t) + x_start = 0.52 * c + # Write glyph file. + with open(filename, 'w') as f: + print >>f, """ + gg::memClear + gg::defReset + gg::tolReset + gg::dispViewReset + """ + print >>f, 'gg::dbCurveBegin -type CUBIC' + for x, y in zip(x_airfoil[1:], y_airfoil[1:]): + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, y, 0.) + print >>f, 'set db_NACA1 [gg::dbCurveEnd]' + print >>f, 'gg::dbCurveBegin -type CUBIC' + for x, y in zip(reversed(x_airfoil[1:]), reversed(y_airfoil[1:])): + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % (x, -y, 0.) + print >>f, 'set db_NACA2 [gg::dbCurveEnd]' + print >>f, 'gg::dbCurveBegin -type CONIC -rho 0.5' + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[1], y_airfoil[1], 0.) + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[1], -y_airfoil[1], 0.) + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' \ + % (x_airfoil[0], y_airfoil[0], 0.) + print >>f, 'set db_NACA3 [gg::dbCurveEnd]' + print >>f, 'gg::dbCurveBegin -type CONIC -rho 0.5' + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[-1], y_airfoil[-1], 0.) + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_airfoil[-1], -y_airfoil[-1], 0.) + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (x_te, 0., 0.) + print >>f, 'set db_NACA4 [gg::dbCurveEnd]' + print >>f, """ + set con_NACA1 [gg::conOnDBEnt $db_NACA1] + set con_NACA2 [gg::conOnDBEnt $db_NACA2] + set con_NACA3 [gg::conOnDBEnt $db_NACA3] + set con_NACA4 [gg::conOnDBEnt $db_NACA4] + """ + print >>f, 'set con_NACA5 [gg::conSplit $con_NACA1 ' \ + '[gg::conGetPt $con_NACA1 -x %f]]' % (x_start) + print >>f, """ + set con_NACA6 [gg::conJoin $con_NACA5 $con_NACA4] + set con_NACA7 [gg::conJoin $con_NACA6 $con_NACA2] + set con_NACA8 [gg::conJoin $con_NACA7 $con_NACA3] + set con_NACA [gg::conJoin $con_NACA1 $con_NACA8] + """ + print >>f, 'gg::conDim $con_NACA %i' % (grid_size[0]) + print >>f, 'set LE_pt [gg::conGetPt $con_NACA -x 0]' + print >>f, 'gg::conSetBreakPt $con_NACA $LE_pt' + print >>f, 'set TE_pt [gg::conGetPt $con_NACA -y 0]' + print >>f, 'gg::conSetBreakPt $con_NACA $TE_pt' + print >>f, 'gg::conBreakPtSpacing $con_NACA -breakpt 1 %f' % \ + (ds_te * c) + print >>f, 'gg::conBreakPtSpacing $con_NACA -breakpt 2 %f' % \ + (ds_le * c) + print >>f, 'set ds_start [ggu::vec3Length [ggu::vec3Sub [' \ + 'gg::conGetPt $con_NACA %i] [gg::conGetPt $con_NACA %i]]]' % \ + (grid_size[0], grid_size[0] - 1) + print >>f, 'gg::conBeginSpacing $con_NACA -sub 1 $ds_start' + print >>f, 'gg::conEndSpacing $con_NACA -sub 3 $ds_start' + print >>f, 'gg::domExtrusionBegin [list $con_NACA] -edge' + print >>f, 'gg::domExtrusionMode HYPERBOLIC' + print >>f, 'gg::domExtrusionAtt -s_init %f -march_plane {0 0 1} ' \ + '-stop_height %f -growth_geometric %f -normal_count 20 ' \ + '-normal_relax 1 -vol_smoothing 0.25' % \ + (ds_normal * c, stop_height * c, stretch_ratio) + print >>f, 'gg::domExtrusionStep -result ExtResult %i' % \ + (grid_size[1] - 1) + print >>f, 'set dom_NACA [gg::domExtrusionEnd]' + print >>f, 'gg::domTransformBegin $dom_NACA -maintain_linkage' + print >>f, 'gg::xformRotate [list 0 0 0] [list 0 0 1] %f' % (-alpha) + print >>f, 'gg::domTransformEnd' + print >>f, 'gg::domTransformBegin $dom_NACA -maintain_linkage' + print >>f, 'gg::xformScale [list 0 0 0] [list %f %f %f]' % \ + (1. / x_te, 1. / x_te, 1. / x_te) + print >>f, 'gg::domTransformEnd' + print >>f, 'gg::dbDelete ALL' + print >>f, 'gg::domExport $dom_NACA \"NACA0012.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + +def grid(**kwargs): + if not os.path.isfile('NACA0012.xyz'): + f = tempfile.NamedTemporaryFile(delete=False) + write_glyph_file(f.name, **kwargs) + subprocess.check_output(["gridgen", "-b", f.name]) + os.unlink(f.name) + +def target_state(g, mach_number, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0][:,:,:,1] = mach_number + return s.fromprimitive(gamma) + +if __name__ == '__main__': + grid(grid_size=[512, 448]) + g = p3d.fromfile('NACA0012.xyz') + target_state(g, mach_number=0.5).save('NACA0012.target.q') diff --git a/examples/OSUMach1.3/config.py b/examples/OSUMach1.3/config.py index 2b61b275..7a926b94 100644 --- a/examples/OSUMach1.3/config.py +++ b/examples/OSUMach1.3/config.py @@ -126,8 +126,8 @@ def find_eigenvalue(self, initial_guess, max_iterations=200, y = self.newton_raphson_func(x) it = it + 1 if it >= max_iterations: - print "Newton-Raphson failed: initial guess = ", initial_guess, \ - ", current guess = ", x, ", current function = ", abs(y) + print("Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y)) self.alpha = x.real - 1.j * abs(x.imag) return self @@ -191,82 +191,82 @@ def get_eigenmode(self, r): rho * u * u_hat_x]) def draw_circular_arc(f, label, p1, p2, c): - print >>f, 'gg::conBegin' - print >>f, 'gg::segBegin -type CIRCULAR_ARC' - print >>f, 'gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]) - print >>f, 'gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]) - print >>f, 'gg::segAddControlPt -alternate CENTER {%f %f %f}' % \ - (c[0], c[1], c[2]) - print >>f, 'gg::segEnd' - print >>f, 'set %s [gg::conEnd]' % (label) + print('gg::conBegin', file=f) + print('gg::segBegin -type CIRCULAR_ARC', file=f) + print('gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]), file=f) + print('gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]), file=f) + print('gg::segAddControlPt -alternate CENTER {%f %f %f}' % \ + (c[0], c[1], c[2]), file=f) + print('gg::segEnd', file=f) + print('set %s [gg::conEnd]' % (label), file=f) return None def draw_line3d(f, label, p1, p2): - print >>f, 'gg::conBegin' - print >>f, 'gg::segBegin -type 3D_LINE' - print >>f, 'gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]) - print >>f, 'gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]) - print >>f, 'gg::segEnd' - print >>f, 'set %s [gg::conEnd]' % (label) + print('gg::conBegin', file=f) + print('gg::segBegin -type 3D_LINE', file=f) + print('gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]), file=f) + print('gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]), file=f) + print('gg::segEnd', file=f) + print('set %s [gg::conEnd]' % (label), file=f) return None def rotate_copy_connector(f, label, p1, p2, angle, new_label=None, replace=False): if replace is True: - print >>f, 'gg::conTransformBegin $%s -maintain_linkage' % (label) + print('gg::conTransformBegin $%s -maintain_linkage' % (label), file=f) else: - print >>f, 'gg::conCopyBegin $%s' % (label) - print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ - (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + print('gg::conCopyBegin $%s' % (label), file=f) + print('gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle), file=f) if replace is True: - print >>f, 'gg::conTransformEnd' + print('gg::conTransformEnd', file=f) else: - print >>f, 'set %s [gg::conCopyEnd]' % (new_label) + print('set %s [gg::conCopyEnd]' % (new_label), file=f) return None def rotate_copy_domain(f, label, p1, p2, angle, new_label=None, replace=False): if replace is True: - print >>f, 'gg::domTransformBegin $%s -maintain_linkage' % (label) + print('gg::domTransformBegin $%s -maintain_linkage' % (label), file=f) else: - print >>f, 'gg::domCopyBegin $%s' % (label) - print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ - (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + print('gg::domCopyBegin $%s' % (label), file=f) + print('gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle), file=f) if replace is True: - print >>f, 'gg::domTransformEnd' + print('gg::domTransformEnd', file=f) else: - print >>f, 'set %s [gg::domCopyEnd]' % (new_label) + print('set %s [gg::domCopyEnd]' % (new_label), file=f) return None def rotate_copy_block(f, label, p1, p2, angle, new_label=None, replace=False): if replace is True: - print >>f, 'gg::blkTransformBegin $%s -maintain_linkage' % (label) + print('gg::blkTransformBegin $%s -maintain_linkage' % (label), file=f) else: - print >>f, 'gg::blkCopyBegin $%s' % (label) - print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ - (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + print('gg::blkCopyBegin $%s' % (label), file=f) + print('gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle), file=f) if replace is True: - print >>f, 'gg::blkTransformEnd' + print('gg::blkTransformEnd', file=f) else: - print >>f, 'set %s [gg::blkCopyEnd]' % (new_label) + print('set %s [gg::blkCopyEnd]' % (new_label), file=f) return None def domain(f, edge1, edge2, edge3, edge4, label): - print >>f, 'gg::domBegin -type STRUCTURED' - print >>f, 'gg::edgeBegin' - print >>f, 'gg::edgeAddCon $%s' % (edge1) - print >>f, 'gg::edgeEnd' - print >>f, 'gg::edgeBegin' - print >>f, 'gg::edgeAddCon $%s' % (edge2) - print >>f, 'gg::edgeEnd' - print >>f, 'gg::edgeBegin' - print >>f, 'gg::edgeAddCon $%s' % (edge3) - print >>f, 'gg::edgeEnd' - print >>f, 'gg::edgeBegin' - print >>f, 'gg::edgeAddCon $%s' % (edge4) - print >>f, 'gg::edgeEnd' - print >>f, 'set %s [gg::domEnd]' % (label) + print('gg::domBegin -type STRUCTURED', file=f) + print('gg::edgeBegin', file=f) + print('gg::edgeAddCon $%s' % (edge1), file=f) + print('gg::edgeEnd', file=f) + print('gg::edgeBegin', file=f) + print('gg::edgeAddCon $%s' % (edge2), file=f) + print('gg::edgeEnd', file=f) + print('gg::edgeBegin', file=f) + print('gg::edgeAddCon $%s' % (edge3), file=f) + print('gg::edgeEnd', file=f) + print('gg::edgeBegin', file=f) + print('gg::edgeAddCon $%s' % (edge4), file=f) + print('gg::edgeEnd', file=f) + print('set %s [gg::domEnd]' % (label), file=f) return None def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, @@ -283,28 +283,28 @@ def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, dz_min = dz_min_fraction * dr_min # Write glyph file. with open(filename, 'w') as f: - print >>f, """ + print(""" gg::memClear gg::defReset gg::tolReset gg::dispViewReset gg::dispGlide FALSE set cwd [file dirname [info script]] - """ + """, file=f) theta = np.linspace(-np.pi / 4., np.pi / 4., 201) if p_inner < 2.: theta += np.pi / 4. - print >>f, 'gg::dbCurveBegin -type CUBIC' + print('gg::dbCurveBegin -type CUBIC', file=f) for theta_ in theta: r = 0.5 * a_inner / \ (abs(np.cos(theta_)) ** p_inner + abs(np.sin(theta_)) ** p_inner) ** (1. / p_inner) - print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ - (r * np.cos(theta_), r * np.sin(theta_), 0.) - print >>f, 'set db_inner_block_E [gg::dbCurveEnd]' - print >>f, """ + print('gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (r * np.cos(theta_), r * np.sin(theta_), 0.), file=f) + print('set db_inner_block_E [gg::dbCurveEnd]', file=f) + print(""" set inner_block_E [gg::conOnDBEnt $db_inner_block_E] - """ + """, file=f) rotate_copy_connector(f, 'inner_block_E', [0., 0., 0.], [0., 0., 1.], 90., 'inner_block_N') rotate_copy_connector(f, 'inner_block_N', [0., 0., 0.], [0., 0., 1.], @@ -312,8 +312,8 @@ def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, rotate_copy_connector(f, 'inner_block_W', [0., 0., 0.], [0., 0., 1.], 90., 'inner_block_S') # Dimension inner block and create domain. - print >>f, 'gg::conDim [list $inner_block_E $inner_block_N ' \ - '$inner_block_W $inner_block_S] %i' % (num_azimuthal / 4 + 1) + print('gg::conDim [list $inner_block_E $inner_block_N ' \ + '$inner_block_W $inner_block_S] %i' % (num_azimuthal / 4 + 1), file=f) domain(f, 'inner_block_S', 'inner_block_E', 'inner_block_N', 'inner_block_W', 'dom_inner') if p_inner < 2.: @@ -328,63 +328,63 @@ def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, [r_se * np.cos(theta_se), r_se * np.sin(theta_se), 0.], [r_outer * np.cos(theta_se), r_outer * np.sin(theta_se), 0.]) # Dimension south-east connector. - print >>f, 'gg::conDim [list $tmp_extrusion_SE] %i' % (num_radial) - print >>f, 'gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ + print('gg::conDim [list $tmp_extrusion_SE] %i' % (num_radial), file=f) + print('gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ ((r_se + num_const_dr * dr_interface) * np.cos(theta_se), - (r_se + num_const_dr * dr_interface) * np.sin(theta_se)) - print >>f, 'gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ - (r_nozzle * np.cos(theta_se), r_nozzle * np.sin(theta_se)) - print >>f, 'gg::conSubConDim $tmp_extrusion_SE [list %i %i %i]' % \ + (r_se + num_const_dr * dr_interface) * np.sin(theta_se)), file=f) + print('gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ + (r_nozzle * np.cos(theta_se), r_nozzle * np.sin(theta_se)), file=f) + print('gg::conSubConDim $tmp_extrusion_SE [list %i %i %i]' % \ (num_const_dr + 1, num_radial_inside_nozzle - num_const_dr + 1, - num_radial - num_radial_inside_nozzle) - print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 3 %f' % (dr_min) - print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 2 %f' % \ - (dr_interface) - print >>f, 'gg::conEndSpacing $tmp_extrusion_SE -sub 2 %f' % (dr_min) - print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 1 %f' % \ - (dr_interface) - print >>f, 'gg::conEndSpacing $tmp_extrusion_SE -sub 1 %f' % \ - (dr_interface) + num_radial - num_radial_inside_nozzle), file=f) + print('gg::conBeginSpacing $tmp_extrusion_SE -sub 3 %f' % (dr_min), file=f) + print('gg::conBeginSpacing $tmp_extrusion_SE -sub 2 %f' % \ + (dr_interface), file=f) + print('gg::conEndSpacing $tmp_extrusion_SE -sub 2 %f' % (dr_min), file=f) + print('gg::conBeginSpacing $tmp_extrusion_SE -sub 1 %f' % \ + (dr_interface), file=f) + print('gg::conEndSpacing $tmp_extrusion_SE -sub 1 %f' % \ + (dr_interface), file=f) if p_inner < 2.: rotate_copy_connector(f, 'tmp_extrusion_SE', [0., 0., 0.], [0., 0., 1.], -45., replace=True) # Extrude to create the outer blocks. - print >>f, """ + print(""" gg::domExtrusionBegin [list $inner_block_E $inner_block_N \ $inner_block_W $inner_block_S] -default HYPERBOLIC gg::domExtrusionAtt -flip gg::domExtrusionAtt -growth_subcon [list [list $tmp_extrusion_SE 1] \ [list $tmp_extrusion_SE 2] [list $tmp_extrusion_SE 3]] - """ - print >>f, 'gg::domExtrusionAtt -stop_height %f' % (r_outer) - print >>f, 'gg::domExtrusionStep %i' % (num_radial) - print >>f, """ + """, file=f) + print('gg::domExtrusionAtt -stop_height %f' % (r_outer), file=f) + print('gg::domExtrusionStep %i' % (num_radial), file=f) + print(""" set dom_outer_blocks [gg::domExtrusionEnd] set dom_outer_E [lindex $dom_outer_blocks 0] set dom_outer_N [lindex $dom_outer_blocks 1] set dom_outer_W [lindex $dom_outer_blocks 2] set dom_outer_S [lindex $dom_outer_blocks 3] unset dom_outer_blocks - """ + """, file=f) if num_axial > 1: # Move domains to axial start coordinate. - print >>f, 'gg::domTransformBegin [list $dom_inner $dom_outer_E ' \ - '$dom_outer_N $dom_outer_W $dom_outer_S] -maintain_linkage' - print >>f, 'gg::xformTranslate {0 0 %f}' % (z_min) - print >>f, 'gg::domTransformEnd' + print('gg::domTransformBegin [list $dom_inner $dom_outer_E ' \ + '$dom_outer_N $dom_outer_W $dom_outer_S] -maintain_linkage', file=f) + print('gg::xformTranslate {0 0 %f}' % (z_min), file=f) + print('gg::domTransformEnd', file=f) # Create the axis connector. draw_line3d(f, 'axis', [0., 0., z_min], [0., 0., z_max]) - print >>f, 'gg::conDim [list $axis] %i' % (num_axial) - print >>f, 'gg::conSetBreakPt $axis {0 0 %f}' % \ - (potential_core_length) - print >>f, 'gg::conBreakPtSpacing $axis -breakpt 1 %f' % (dz_min) + print('gg::conDim [list $axis] %i' % (num_axial), file=f) + print('gg::conSetBreakPt $axis {0 0 %f}' % \ + (potential_core_length), file=f) + print('gg::conBreakPtSpacing $axis -breakpt 1 %f' % (dz_min), file=f) # Extrude blocks. - print >>f, 'gg::blkExtrusionBegin [list $dom_inner $dom_outer_E ' \ - '$dom_outer_N $dom_outer_W $dom_outer_S] -default PATH' - print >>f, 'gg::blkExtrusionAtt -path_connector ' \ - '[list [list $axis 1] [list $axis 2]]' - print >>f, 'gg::blkExtrusionStep %i' % (num_axial) - print >>f, """ + print('gg::blkExtrusionBegin [list $dom_inner $dom_outer_E ' \ + '$dom_outer_N $dom_outer_W $dom_outer_S] -default PATH', file=f) + print('gg::blkExtrusionAtt -path_connector ' \ + '[list [list $axis 1] [list $axis 2]]', file=f) + print('gg::blkExtrusionStep %i' % (num_axial), file=f) + print(""" set all_blocks [gg::blkExtrusionEnd] set blk_inner [lindex $all_blocks 0] set blk_outer_E [lindex $all_blocks 1] @@ -392,19 +392,19 @@ def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, set blk_outer_W [lindex $all_blocks 3] set blk_outer_S [lindex $all_blocks 4] unset all_blocks - """ + """, file=f) # Re-orient blocks. - print >>f, 'gg::blkSpecifyIJK [list $blk_outer_E $blk_outer_N ' \ - '$blk_outer_W $blk_outer_S] 5 4 1' - print >>f, 'gg::dbDelete ALL' + print('gg::blkSpecifyIJK [list $blk_outer_E $blk_outer_N ' \ + '$blk_outer_W $blk_outer_S] 5 4 1', file=f) + print('gg::dbDelete ALL', file=f) # Save PLOT3D grid file. - print >>f, 'gg::blkExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ - '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + print('gg::blkExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE', file=f) else: - print >>f, 'gg::dbDelete ALL' + print('gg::dbDelete ALL', file=f) # Save PLOT3D grid file. - print >>f, 'gg::domExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ - '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + print('gg::domExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE', file=f) def grid(**kwargs): if not os.path.isfile('OSUMach1.3.xyz'): @@ -449,7 +449,7 @@ def eigenmodes(mach_number=1.3, theta_j=0.04, show_progress=True): modes = [[InstabilityMode() for n_ in n] for St_ in St] if show_progress: from progressbar import ProgressBar, Percentage, Bar, ETA - print 'Computing eigenmodes:' + print('Computing eigenmodes:') p = ProgressBar(widgets = [Percentage(), ' ', Bar('=', left = '[', right = ']'), ' ', ETA()], maxval = alpha.size).start() @@ -534,9 +534,9 @@ def target_mollifier(g): fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) kmin, kmax = p3d.find_extents(z, z_min, z_max) imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'targetRegion.' + block_code[i], 'COST_TARGET', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f def control_mollifier(g): @@ -561,9 +561,9 @@ def control_mollifier(g): fi[:,k,j,0] *= p3d.tanh_support(r[:,k], r_min, r_max, 10., 0.2) kmin, kmax = p3d.find_extents(z, z_min, z_max) imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'controlRegion.' + block_code[i], 'ACTUATOR', - i + 1, 0, imin, imax, 1, -1, kmin, kmax) + i + 1, 0, imin, imax, 1, -1, kmin, kmax)) return f if __name__ == '__main__': diff --git a/examples/OSUMach1.3/config.py2 b/examples/OSUMach1.3/config.py2 new file mode 100644 index 00000000..2b61b275 --- /dev/null +++ b/examples/OSUMach1.3/config.py2 @@ -0,0 +1,584 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d +import tempfile +import subprocess +import os +import os.path +import numpy.random as random + +EPSILON = np.finfo(float).eps + +class InstabilityMode: + + def __init__(self, n=0, omega=0., theta=1., mach_number=0., + r_nozzle=0.5, gamma=1.4): + self.n = n + self.omega = omega + self.theta = theta + self.mach_number = mach_number + self.r_nozzle = r_nozzle + self.gamma = gamma + + def update(self): + self._temperature_ratio = 1. / (1. + 0.5 * (self.gamma - 1.) * + self.mach_number ** 2) + self._u_j = self.mach_number * np.sqrt(self._temperature_ratio) + return self + + def set_domain(self, r, r_lower, r_match, r_upper): + self._r = r + i_lower = np.argmin(np.abs(self._r - r_lower)) + i_match = np.argmin(np.abs(self._r - r_match)) + i_upper = np.argmin(np.abs(self._r - r_upper)) + self._num_steps_inner = i_match - i_lower + self._num_steps_outer = i_upper - i_match + self._r_lower = self._r[i_lower] + self._r_match = self._r[i_match] + self._r_upper = self._r[i_upper] + return self + + def mean_flow(self, r): + u = 0.5 * (1. + np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle))) + u_dot = -0.125 / self.theta * (1. - np.tanh(0.25 / self.theta * ( + self.r_nozzle / (r + EPSILON) - r / self.r_nozzle)) ** 2) * ( + self.r_nozzle / (r + EPSILON) ** 2 + 1. / self.r_nozzle) + # u, \rho, a, du/dr, d\rho/dr + mean_flow = np.array([np.empty_like(r) for i in range(5)]) + mean_flow[0] = self.mach_number * np.sqrt(self._temperature_ratio) * u + mean_flow[1] = 1. / self._temperature_ratio / ( + 0.5 * (self.gamma - 1.) * u * (1. - u) * self.mach_number ** 2 + + u + (1. - u) / self._temperature_ratio) + mean_flow[2] = np.sqrt(1. / mean_flow[1]) + mean_flow[3] = self.mach_number * np.sqrt(self._temperature_ratio) * \ + u_dot + mean_flow[4] = -self._temperature_ratio * mean_flow[1] ** 2 * u_dot * ( + 0.5 * (self.gamma - 1.) * (1. - 2. * u) * self.mach_number ** 2 + + 1. - 1. / self._temperature_ratio) + return mean_flow + + def rayleigh_rhs(self, r, p_hat, alpha): + u, rho, a, u_r, rho_r = self.mean_flow(r) + return np.array([p_hat[1], + - (1. / r - rho_r / rho + 2. * alpha / + (self.omega - alpha * u) * u_r) * p_hat[1] - + ((self.omega - alpha * u) ** 2 / a ** 2 - + self.n ** 2 / r ** 2 - alpha ** 2) * p_hat[0]]) + + def inner_solution(self, r, alpha): + import scipy.special + eta = np.sqrt((self.omega - alpha * self._u_j) ** 2 / + self._temperature_ratio - alpha ** 2) + return np.array([scipy.special.jn(self.n, eta * r), + eta * 0.5 * (scipy.special.jn(self.n - 1, eta * r) - + scipy.special.jn(self.n + 1, eta * r))]) + + def outer_solution(self, r, alpha): + import scipy.special + eta = np.sqrt(self.omega ** 2 - alpha ** 2) + return np.array([scipy.special.hankel1(self.n, + np.sign(eta.imag) * eta * r), + np.sign(eta.imag) * eta * 0.5 * ( + scipy.special.hankel1(self.n - 1, + np.sign(eta.imag) * + eta * r) - + scipy.special.hankel1(self.n + 1, + np.sign(eta.imag) * + eta * r))]) + + def newton_raphson_func(self, alpha): + from scipy.integrate import ode + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(alpha) + # Inner solution + integrator.set_initial_value(self.inner_solution(self._r_lower, alpha), + self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + integrator.integrate(integrator.t + dr) + inner_solution = integrator.y + # Outer solution + integrator.set_initial_value(self.outer_solution(self._r_upper, alpha), + self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + integrator.integrate(integrator.t - dr) + outer_solution = integrator.y + if abs(outer_solution[0] / inner_solution[0]) < 1e-6: + return inner_solution[1] - outer_solution[1] * \ + inner_solution[0] / outer_solution[0] + return inner_solution[1] * outer_solution[0] / inner_solution[0] - \ + outer_solution[1] + + def find_eigenvalue(self, initial_guess, max_iterations=200, + tolerance=1e-10): + x = initial_guess + y = self.newton_raphson_func(x) + it = 1 + while abs(y) > tolerance and it <= max_iterations: # Newton-Raphson + dx = random.uniform(1e-10, 1e-8) + 1j * \ + random.uniform(1e-10, 1e-8) # step size for derivative + x = x - dx * y / (self.newton_raphson_func(x + dx) - y) + y = self.newton_raphson_func(x) + it = it + 1 + if it >= max_iterations: + print "Newton-Raphson failed: initial guess = ", initial_guess, \ + ", current guess = ", x, ", current function = ", abs(y) + self.alpha = x.real - 1.j * abs(x.imag) + return self + + def find_eigenfunction(self, tolerance=1e-8): + from scipy.integrate import ode + from scipy.interpolate import interp1d + integrator = ode(self.rayleigh_rhs) + integrator.set_integrator('zvode', method='bdf', + order=15).set_f_params(self.alpha) + p_hat = np.array([np.empty_like(self._r) for i in range(2)], + dtype='complex128') + i_lower = np.argmin(np.abs(self._r - self._r_lower)) + p_hat[:,:i_lower] = self.inner_solution(self._r[:i_lower], self.alpha) + i = i_lower + integrator.set_initial_value(self.inner_solution( + self._r_lower, self.alpha), self._r_lower) + dr = (self._r_match - self._r_lower) / self._num_steps_inner + while integrator.successful() and \ + integrator.t < self._r_match - 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t + dr) + i += 1 + p_hat[:,i] = integrator.y + i_upper = np.argmin(np.abs(self._r - self._r_upper)) + p_hat[:,i_upper:] = self.outer_solution(self._r[i_upper:], self.alpha) + i = i_upper + integrator.set_initial_value(self.outer_solution( + self._r_upper, self.alpha), self._r_upper) + dr = (self._r_upper - self._r_match) / self._num_steps_outer + while integrator.successful() and \ + integrator.t > self._r_match + 0.5 * dr: + p_hat[:,i] = integrator.y + integrator.integrate(integrator.t - dr) + i -= 1 + outer_solution = integrator.y + scaling_factor = integrator.y[0] / p_hat[0,i] + scaling_factor_inverse = 1. / scaling_factor + if abs(scaling_factor) < 1e-6: + p_hat[:,i+1:] *= scaling_factor_inverse + else: + p_hat[:,:i+1] *= scaling_factor + assert abs(p_hat[1,i] - integrator.y[1]) < tolerance + self.p_hat_dot = interp1d(self._r, p_hat[1,:], kind='linear') + self.p_hat = interp1d(self._r, p_hat[0,:], kind='linear') + return self + + def get_eigenmode(self, r): + u, rho, a, u_r, rho_r = self.mean_flow(r) + p_hat = self.p_hat(r) + p_hat_r = self.p_hat_dot(r) + omega = self.omega - self.alpha * u + u_hat_r = 1. / (1.j * rho * omega) * p_hat_r + u_hat_x = self.alpha * p_hat / (rho * omega) + \ + u_hat_r / (1.j * omega) * u_r + rho_hat = p_hat / a ** 2 + u_hat_r / (1.j * omega) * rho_r + return np.array([rho_hat, + rho * u_hat_r, + self.n * p_hat / (r * omega + EPSILON), + rho_hat * u + rho * u_hat_x, + p_hat / (self.gamma - 1.) + 0.5 * rho_hat * u ** 2 + + rho * u * u_hat_x]) + +def draw_circular_arc(f, label, p1, p2, c): + print >>f, 'gg::conBegin' + print >>f, 'gg::segBegin -type CIRCULAR_ARC' + print >>f, 'gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]) + print >>f, 'gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]) + print >>f, 'gg::segAddControlPt -alternate CENTER {%f %f %f}' % \ + (c[0], c[1], c[2]) + print >>f, 'gg::segEnd' + print >>f, 'set %s [gg::conEnd]' % (label) + return None + +def draw_line3d(f, label, p1, p2): + print >>f, 'gg::conBegin' + print >>f, 'gg::segBegin -type 3D_LINE' + print >>f, 'gg::segAddControlPt {%f %f %f}' % (p1[0], p1[1], p1[2]) + print >>f, 'gg::segAddControlPt {%f %f %f}' % (p2[0], p2[1], p2[2]) + print >>f, 'gg::segEnd' + print >>f, 'set %s [gg::conEnd]' % (label) + return None + +def rotate_copy_connector(f, label, p1, p2, angle, new_label=None, + replace=False): + if replace is True: + print >>f, 'gg::conTransformBegin $%s -maintain_linkage' % (label) + else: + print >>f, 'gg::conCopyBegin $%s' % (label) + print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + if replace is True: + print >>f, 'gg::conTransformEnd' + else: + print >>f, 'set %s [gg::conCopyEnd]' % (new_label) + return None + +def rotate_copy_domain(f, label, p1, p2, angle, new_label=None, + replace=False): + if replace is True: + print >>f, 'gg::domTransformBegin $%s -maintain_linkage' % (label) + else: + print >>f, 'gg::domCopyBegin $%s' % (label) + print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + if replace is True: + print >>f, 'gg::domTransformEnd' + else: + print >>f, 'set %s [gg::domCopyEnd]' % (new_label) + return None + +def rotate_copy_block(f, label, p1, p2, angle, new_label=None, + replace=False): + if replace is True: + print >>f, 'gg::blkTransformBegin $%s -maintain_linkage' % (label) + else: + print >>f, 'gg::blkCopyBegin $%s' % (label) + print >>f, 'gg::xformRotate {%f %f %f} {%f %f %f} %f' % \ + (p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], angle) + if replace is True: + print >>f, 'gg::blkTransformEnd' + else: + print >>f, 'set %s [gg::blkCopyEnd]' % (new_label) + return None + +def domain(f, edge1, edge2, edge3, edge4, label): + print >>f, 'gg::domBegin -type STRUCTURED' + print >>f, 'gg::edgeBegin' + print >>f, 'gg::edgeAddCon $%s' % (edge1) + print >>f, 'gg::edgeEnd' + print >>f, 'gg::edgeBegin' + print >>f, 'gg::edgeAddCon $%s' % (edge2) + print >>f, 'gg::edgeEnd' + print >>f, 'gg::edgeBegin' + print >>f, 'gg::edgeAddCon $%s' % (edge3) + print >>f, 'gg::edgeEnd' + print >>f, 'gg::edgeBegin' + print >>f, 'gg::edgeAddCon $%s' % (edge4) + print >>f, 'gg::edgeEnd' + print >>f, 'set %s [gg::domEnd]' % (label) + return None + +def write_glyph_file(filename, num_axial=1, num_radial=241, num_azimuthal=128, + a_inner=0.24, p_inner=1.14, r_nozzle=0.5, r_outer=12.5, + z_min=-10., z_max=34., potential_core_length=8., + fraction_inside_nozzle=0.2, num_const_dr=4, + dr_min_fraction=1., dz_min_fraction=2.25, + interface_ds_ratio=1.): + assert num_azimuthal % 4 == 0 + num_radial_inside_nozzle = int(np.floor(fraction_inside_nozzle * + num_radial)) + dr_interface = interface_ds_ratio * a_inner / (num_azimuthal / 4) + dr_min = dr_min_fraction * a_inner / (num_azimuthal / 4) + dz_min = dz_min_fraction * dr_min + # Write glyph file. + with open(filename, 'w') as f: + print >>f, """ + gg::memClear + gg::defReset + gg::tolReset + gg::dispViewReset + gg::dispGlide FALSE + set cwd [file dirname [info script]] + """ + theta = np.linspace(-np.pi / 4., np.pi / 4., 201) + if p_inner < 2.: + theta += np.pi / 4. + print >>f, 'gg::dbCurveBegin -type CUBIC' + for theta_ in theta: + r = 0.5 * a_inner / \ + (abs(np.cos(theta_)) ** p_inner + + abs(np.sin(theta_)) ** p_inner) ** (1. / p_inner) + print >>f, 'gg::dbCurveAddPt {%.6f %.6f %.6f}' % \ + (r * np.cos(theta_), r * np.sin(theta_), 0.) + print >>f, 'set db_inner_block_E [gg::dbCurveEnd]' + print >>f, """ + set inner_block_E [gg::conOnDBEnt $db_inner_block_E] + """ + rotate_copy_connector(f, 'inner_block_E', [0., 0., 0.], [0., 0., 1.], + 90., 'inner_block_N') + rotate_copy_connector(f, 'inner_block_N', [0., 0., 0.], [0., 0., 1.], + 90., 'inner_block_W') + rotate_copy_connector(f, 'inner_block_W', [0., 0., 0.], [0., 0., 1.], + 90., 'inner_block_S') + # Dimension inner block and create domain. + print >>f, 'gg::conDim [list $inner_block_E $inner_block_N ' \ + '$inner_block_W $inner_block_S] %i' % (num_azimuthal / 4 + 1) + domain(f, 'inner_block_S', 'inner_block_E', 'inner_block_N', + 'inner_block_W', 'dom_inner') + if p_inner < 2.: + rotate_copy_domain(f, 'dom_inner', [0., 0., 0.], [0., 0., 1.], + -45., replace=True) + # Create south-east connector to specify extrusion step size. + theta_se = theta[0] + r_se = 0.5 * a_inner / \ + (abs(np.cos(theta_se)) ** p_inner + + abs(np.sin(theta_se)) ** p_inner) ** (1. / p_inner) + draw_line3d(f, 'tmp_extrusion_SE', + [r_se * np.cos(theta_se), r_se * np.sin(theta_se), 0.], + [r_outer * np.cos(theta_se), r_outer * np.sin(theta_se), 0.]) + # Dimension south-east connector. + print >>f, 'gg::conDim [list $tmp_extrusion_SE] %i' % (num_radial) + print >>f, 'gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ + ((r_se + num_const_dr * dr_interface) * np.cos(theta_se), + (r_se + num_const_dr * dr_interface) * np.sin(theta_se)) + print >>f, 'gg::conSetBreakPt $tmp_extrusion_SE {%f %f 0}' % \ + (r_nozzle * np.cos(theta_se), r_nozzle * np.sin(theta_se)) + print >>f, 'gg::conSubConDim $tmp_extrusion_SE [list %i %i %i]' % \ + (num_const_dr + 1, num_radial_inside_nozzle - num_const_dr + 1, + num_radial - num_radial_inside_nozzle) + print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 3 %f' % (dr_min) + print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 2 %f' % \ + (dr_interface) + print >>f, 'gg::conEndSpacing $tmp_extrusion_SE -sub 2 %f' % (dr_min) + print >>f, 'gg::conBeginSpacing $tmp_extrusion_SE -sub 1 %f' % \ + (dr_interface) + print >>f, 'gg::conEndSpacing $tmp_extrusion_SE -sub 1 %f' % \ + (dr_interface) + if p_inner < 2.: + rotate_copy_connector(f, 'tmp_extrusion_SE', [0., 0., 0.], + [0., 0., 1.], -45., replace=True) + # Extrude to create the outer blocks. + print >>f, """ + gg::domExtrusionBegin [list $inner_block_E $inner_block_N \ + $inner_block_W $inner_block_S] -default HYPERBOLIC + gg::domExtrusionAtt -flip + gg::domExtrusionAtt -growth_subcon [list [list $tmp_extrusion_SE 1] \ + [list $tmp_extrusion_SE 2] [list $tmp_extrusion_SE 3]] + """ + print >>f, 'gg::domExtrusionAtt -stop_height %f' % (r_outer) + print >>f, 'gg::domExtrusionStep %i' % (num_radial) + print >>f, """ + set dom_outer_blocks [gg::domExtrusionEnd] + set dom_outer_E [lindex $dom_outer_blocks 0] + set dom_outer_N [lindex $dom_outer_blocks 1] + set dom_outer_W [lindex $dom_outer_blocks 2] + set dom_outer_S [lindex $dom_outer_blocks 3] + unset dom_outer_blocks + """ + if num_axial > 1: + # Move domains to axial start coordinate. + print >>f, 'gg::domTransformBegin [list $dom_inner $dom_outer_E ' \ + '$dom_outer_N $dom_outer_W $dom_outer_S] -maintain_linkage' + print >>f, 'gg::xformTranslate {0 0 %f}' % (z_min) + print >>f, 'gg::domTransformEnd' + # Create the axis connector. + draw_line3d(f, 'axis', [0., 0., z_min], [0., 0., z_max]) + print >>f, 'gg::conDim [list $axis] %i' % (num_axial) + print >>f, 'gg::conSetBreakPt $axis {0 0 %f}' % \ + (potential_core_length) + print >>f, 'gg::conBreakPtSpacing $axis -breakpt 1 %f' % (dz_min) + # Extrude blocks. + print >>f, 'gg::blkExtrusionBegin [list $dom_inner $dom_outer_E ' \ + '$dom_outer_N $dom_outer_W $dom_outer_S] -default PATH' + print >>f, 'gg::blkExtrusionAtt -path_connector ' \ + '[list [list $axis 1] [list $axis 2]]' + print >>f, 'gg::blkExtrusionStep %i' % (num_axial) + print >>f, """ + set all_blocks [gg::blkExtrusionEnd] + set blk_inner [lindex $all_blocks 0] + set blk_outer_E [lindex $all_blocks 1] + set blk_outer_N [lindex $all_blocks 2] + set blk_outer_W [lindex $all_blocks 3] + set blk_outer_S [lindex $all_blocks 4] + unset all_blocks + """ + # Re-orient blocks. + print >>f, 'gg::blkSpecifyIJK [list $blk_outer_E $blk_outer_N ' \ + '$blk_outer_W $blk_outer_S] 5 4 1' + print >>f, 'gg::dbDelete ALL' + # Save PLOT3D grid file. + print >>f, 'gg::blkExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + else: + print >>f, 'gg::dbDelete ALL' + # Save PLOT3D grid file. + print >>f, 'gg::domExport ALL \"OSUMach1.3.xyz\" -style PLOT3D ' \ + '-form UNFORMATTED -precision DOUBLE -endian NATIVE' + +def grid(**kwargs): + if not os.path.isfile('OSUMach1.3.xyz'): + f = tempfile.NamedTemporaryFile(delete=False) + write_glyph_file(f.name, **kwargs) + subprocess.check_output(["gridgen", "-b", f.name]) + os.unlink(f.name) + +def target_state(g, mach_number=1.3, theta_j=0.04, S=0.03, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + temperature_ratio = 1. / (1. + 0.5 * (gamma - 1.) * mach_number ** 2) + u_j = mach_number * np.sqrt(temperature_ratio) + for i, xyz in enumerate(g.xyz): + r = np.sqrt(xyz[:,:,0,0] ** 2 + xyz[:,:,0,1] ** 2) / 0.5 + EPSILON + z = xyz[0,0,:,2] + theta = theta_j + S * np.where(z > 0., z, np.zeros_like(z)) + for k in range(z.size): + s.q[i][:,:,k,3] = 0.5 * u_j * (1. + np.tanh(0.25 / theta[k] * + (1. / r - r))) + s.q[i][:,:,:,0] = 1. / (0.5 * (gamma - 1.) * s.q[i][:,:,:,3] / u_j * + (1. - s.q[i][:,:,:,3] / u_j) * + mach_number ** 2 + s.q[i][:,:,:,3] / u_j + + (1. - s.q[i][:,:,:,3] / u_j) / + temperature_ratio) / temperature_ratio + return s.fromprimitive(gamma) + +def eigenmodes(mach_number=1.3, theta_j=0.04, show_progress=True): + u_j = InstabilityMode(mach_number=mach_number, + theta=theta_j).update().mean_flow(EPSILON)[0] + n = np.arange(1, 6) + St = np.array([0.43, 0.51, 0.61, 0.69, 0.74, 0.88]) + alpha = np.empty([n.size, St.size], dtype='complex128') + r_lower = 0.025 + r_match = 0.25 + r_upper = 3. + r = np.linspace(0., r_lower, 5001) + r = np.append(r[:-1], np.linspace(r_lower, r_match, 5001)) + r = np.append(r[:-1], np.linspace(r_match, r_upper, 5001)) + r = np.append(r[:-1], np.linspace(r_upper, 15., 5001)) + # Initialize eigenmodes. + initial_guess = 1. - 1.j + modes = [[InstabilityMode() for n_ in n] for St_ in St] + if show_progress: + from progressbar import ProgressBar, Percentage, Bar, ETA + print 'Computing eigenmodes:' + p = ProgressBar(widgets = [Percentage(), ' ', + Bar('=', left = '[', right = ']'), ' ', + ETA()], maxval = alpha.size).start() + for j, St_ in enumerate(St): + guess = initial_guess + for i, n_ in enumerate(n): + modes[j][i] = InstabilityMode( + mach_number=mach_number, theta=theta_j, n=n_, + omega=2. * np.pi * u_j * St_).update().set_domain( + r, r_lower, r_match, r_upper) + modes[j][i].find_eigenvalue(guess).find_eigenfunction() + guess = alpha[i,j] = modes[j][i].alpha + if i == 0: + initial_guess = modes[j][i].alpha + if show_progress: + p.update(i + n.size * j) + if show_progress: + p.finish() + return modes + +def extract_inflow(g, k=43): + n = g.get_size() + n[:,2] = k + gi = p3d.Grid().set_size(n, True) + for i, xyz in enumerate(g.xyz): + gi.xyz[i] = xyz[:,:,:k,:] + return gi + +def inflow_perturbations(g, modes): + phi_p = 2. * np.pi * random.rand(len(modes)) + phi_n = 2. * np.pi * random.rand(len(modes)) + sr = p3d.Solution().copy_from(g) + si = p3d.Solution().copy_from(g) + sr._format.aux_header[1] = si._format.aux_header[1] = modes[0].omega + for i in range(g.nblocks): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + theta = np.arctan2(g.xyz[i][:,:,0,1], g.xyz[i][:,:,0,0]) + z = g.xyz[i][0,0,:,2] + si.q[i].fill(0.) + sr.q[i].fill(0.) + for j, mode in enumerate(modes): + q = mode.get_eigenmode(r) + n = mode.n + for l in range(q.shape[0]): + if l == 2: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) - \ + np.exp(-1.j * n * theta + phi_n[j]) + else: + q[l] *= np.exp(1.j * n * theta + phi_p[j]) + \ + np.exp(-1.j * n * theta + phi_n[j]) + u = q[1] * np.cos(theta) - q[2] * np.sin(theta) + v = q[1] * np.sin(theta) + q[2] * np.cos(theta) + q[1] = u + q[2] = v + for l in range(q.shape[0]): + for k, z_ in enumerate(z): + sr.q[i][:,:,k,l] += np.real( + q[l] * np.exp(1.j * mode.alpha * z_)) + si.q[i][:,:,k,l] += np.imag( + q[l] * np.exp(1.j * mode.alpha * z_)) + return sr, si + +def target_mollifier(g): + z_min = 0. + z_max = 24. + r_min = 7. + r_max = 9. + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.tanh_support(z, z_min, z_max, 40., 0.2) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.cubic_bspline_support(r[:,k], r_min, r_max) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion.' + block_code[i], 'COST_TARGET', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +def control_mollifier(g): + z_min = 1. + z_max = 3. + r_min = 0.3 + r_max = 0.7 + f = p3d.Function().copy_from(g) + z = g.xyz[0][0,0,:,2] + n = f.get_size() + block_code = ['IB', 'E', 'N', 'W', 'S'] + for i, fi in enumerate(f.f): + r = np.sqrt(g.xyz[i][:,:,0,0] ** 2 + g.xyz[i][:,:,0,1] ** 2) + if r.max() < r_min or r.min() > r_max: + fi.fill(0.) + continue + fi.fill(1.) + for k in range(n[i][1]): + for j in range(n[i][0]): + fi[j,k,:,0] *= p3d.cubic_bspline_support(z, z_min, z_max) + for j in range(n[i][2]): + fi[:,k,j,0] *= p3d.tanh_support(r[:,k], r_min, r_max, 10., 0.2) + kmin, kmax = p3d.find_extents(z, z_min, z_max) + imin, imax = p3d.find_extents(np.mean(r, axis=1), r_min, r_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion.' + block_code[i], 'ACTUATOR', + i + 1, 0, imin, imax, 1, -1, kmin, kmax) + return f + +if __name__ == '__main__': + from numpy.linalg import det + # grid(num_axial=481, num_radial=281, num_azimuthal=192, + # p_inner=1.12148531779, interface_ds_ratio=0.999793250757) + grid(num_axial=481) + g = p3d.fromfile('OSUMach1.3.xyz') + target_state(g).save('OSUMach1.3.target.q') + target_mollifier(g).save('OSUMach1.3.target_mollifier.f') + control_mollifier(g).save('OSUMach1.3.control_mollifier.f') + gi = extract_inflow(g) + gi.save('OSUMach1.3.inflow.xyz') + modes = eigenmodes() + for i, mode in enumerate(modes): + sr, si = inflow_perturbations(gi, mode) + sr.save('OSUMach1.3-%02d.eigenmode_real.q' % (i + 1)) + si.save('OSUMach1.3-%02d.eigenmode_imag.q' % (i + 1)) diff --git a/examples/OneDWave/config.py b/examples/OneDWave/config.py index 77d2f85c..81e2363a 100644 --- a/examples/OneDWave/config.py +++ b/examples/OneDWave/config.py @@ -29,8 +29,8 @@ def target_mollifier(g): g.xyz[0][:,j,0,0], x_min, x_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -49,8 +49,8 @@ def control_mollifier(g): g.xyz[0][i,:,0,1], y_min, y_max,5,0.2) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def state_mollifier(g): diff --git a/examples/OneDWave/config.py2 b/examples/OneDWave/config.py2 new file mode 100644 index 00000000..77d2f85c --- /dev/null +++ b/examples/OneDWave/config.py2 @@ -0,0 +1,118 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def grid(size): + x_min = -2. + x_max = 22. + y_min = -2. + y_max = 7. + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0]) + y = np.linspace(y_min, y_max, g.size[0,1]) + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def target_mollifier(g): + x_min = 15. + x_max = 18. + y_min = 0. + y_max = 5. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.tanh_support( + g.xyz[0][i,:,0,1], y_min, y_max, 5., 0.2) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 3. + x_max = 6. + y_min = 0. + y_max = 5. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.tanh_support( + g.xyz[0][i,:,0,1], y_min, y_max,5,0.2) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def state_mollifier(g): + x_min = -10. + x_max = 10. + y_min = 0. + y_max = 5. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.tanh_support( + g.xyz[0][:,j,0,0], x_min, x_max, 20, 0.5, False) +# for i in range(n[0]): +# f.f[0][i,:,0,0] *= p3d.tanh_support( +# g.xyz[0][i,:,0,1], y_min, y_max,5,0.2) + f.f[0] /= np.max(f.f[0]) +# imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) +# jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + f.f[0][:,:,:,0] = s.toprimitive().q[0][:,:,:,4] + return f + +def random_solution(g,time=0.0,timestep=0): + + gamma = 1.4 + s = p3d.Solution().copy_from(g).quiescent(gamma) + s.q[0] *= 0.0 + n = s.get_size(0) + s.q[0][:,:,0,0] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,1] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,2] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,4] = ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,4] *= (gamma-1.)/gamma * s.q[0][:,:,0,0] + + s.time = time + s._format.aux_header[0] = timestep + + return s + +def add_random_perturbation(s_old): + + gamma = 1.4 + s = s_old.copy() + n = s.get_size(0) + s.q[0][:,:,0,0] += ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,1] += ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,2] += ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + s.q[0][:,:,0,4] += ( 2.0 * np.random.rand(n[0],n[1]) - 1.0 ) * 1.0e-4 + + return s + +if __name__ == '__main__': + g = grid([201, 51]) + g.save('OneDWave.xyz') + p3d.Solution().copy_from(g).quiescent(1.4).fromprimitive().save('OneDWave.ic.q') + + dt = 5.0e-2 + target_mollifier(g).save('OneDWave.target_mollifier.f') + control_mollifier(g).save('OneDWave.control_mollifier.f') + state_mollifier(g).save('OneDWave.ic_mollifier.f') diff --git a/examples/TDML/config.py b/examples/TDML/config.py new file mode 100644 index 00000000..a6bc8718 --- /dev/null +++ b/examples/TDML/config.py @@ -0,0 +1,98 @@ +#ini!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def mapping_function(s, b, c, sigma): + from scipy.special import erf + return ((s - 0.5) * (1.0 + 2.0 * b) - b * sigma * + (np.exp(- ((s - 0.5 + c) / sigma) ** 2) / np.sqrt(np.pi) + + ((s - 0.5 + c) / sigma) * erf((s - 0.5 + c) / sigma) - + np.exp(- ((s - 0.5 - c) / sigma) ** 2) / np.sqrt(np.pi) - + ((s - 0.5 - c) / sigma) * erf((s - 0.5 - c) / sigma))) / \ + (0.5 + b - b * sigma * (np.exp(- ((0.5 + c) / sigma) ** 2) / + np.sqrt(np.pi) + ((0.5 + c) / sigma) * + erf((0.5 + c) / sigma) - + np.exp(- ((0.5 - c) / sigma) ** 2) / + np.sqrt(np.pi) - ((0.5 - c) / sigma) * + erf((0.5 - c) / sigma))) + +def grid(size, N=16): + x_min = 0. + x_max = 7.0 * N + y_min = -3.5 * N + y_max = 3.5 * N + g = p3d.Grid().set_size(size, True) + # x = x_min + 0.5 * (x_max - x_min) * (1. + mapping_function( + # np.linspace(0., 1., g.size[0,0]), 80., 0.58, 0.07)) + x = np.linspace(x_min, x_max, g.size[0,0] + 1)[:-1] + y = y_min + 0.5 * (y_max - y_min) * (1. + mapping_function( + np.linspace(0., 1., g.size[0,1]), 20., 0.62, 0.2)) + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def target_state(g, u1, u2, S, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i, xyz in enumerate(g.xyz): + x = xyz[:,:,:,0] + s.q[i][:,:,:,1] = u2 + 0.5 * (u1 - u2) * ( + 1. + np.tanh(2. * xyz[:,:,:,1] / \ + (1. + S * np.where(x > 0., x, np.zeros_like(x))))) + return s.fromprimitive(gamma) + +def initial_condition(g, u1, u2, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i, xyz in enumerate(g.xyz): + s.q[i][:,:,:,1] = u2 + 0.5 * (u1 - u2) * ( + 1. + np.tanh(2. * xyz[:,:,:,1])) + return s.fromprimitive(gamma) + +def target_mollifier(g): + x_min = 0. + x_max = 100. + y_min = -74. + y_max = -66. + f = p3d.Function().copy_from(g) + for i, xyz in enumerate(g.xyz): + f.f[i][:,:,:,0] = p3d.tanh_support(xyz[:,:,:,0], x_min, x_max, + 80., 0.14) * \ + p3d.cubic_bspline_support(xyz[:,:,:,1], y_min, y_max) + imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) + if imin and imax and jmin and jmax: + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', i + 1, 0, + imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 7. + y_min = -3. + y_max = 3. + f = p3d.Function().copy_from(g) + for i, xyz in enumerate(g.xyz): + f.f[i][:,:,:,0] = p3d.tanh_support( + xyz[:,:,:,0], x_min, x_max, 20., 0.8) * p3d.tanh_support( + xyz[:,:,:,1], y_min, y_max, 20., 0.8) + imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) + if imin and imax and jmin and jmax: + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', i + 1, 0, + imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + s = s.toprimitive() + for i, q in enumerate(s.q): + f.f[i][:,:,:,0] = q[:,:,:,4] + return f + +if __name__ == '__main__': + g = grid([961, 641]) + g.save('WeiFreundSDML.xyz') + initial_condition(g, u1=0.9, u2=0.2).save('WeiFreundSDML.ic.q') + target_state(g, u1=0.9, u2=0.2, S=0.05).save('WeiFreundSDML.target.q') + target_mollifier(g).save('WeiFreundSDML.target_mollifier.f') + control_mollifier(g).save('WeiFreundSDML.control_mollifier.f') diff --git a/examples/TestForcing/config.py b/examples/TestForcing/config.py index f16ad3c3..8a4dc25b 100644 --- a/examples/TestForcing/config.py +++ b/examples/TestForcing/config.py @@ -23,8 +23,8 @@ def target_mollifier(g): n = f.get_size(0) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -37,8 +37,8 @@ def control_mollifier(g): n = f.get_size(0) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/TestForcing/config.py2 b/examples/TestForcing/config.py2 new file mode 100644 index 00000000..f16ad3c3 --- /dev/null +++ b/examples/TestForcing/config.py2 @@ -0,0 +1,53 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def grid(size): + x_min = 0. + x_max = 1. + y_min = 0. + y_max = 1. + g = p3d.Grid().set_size(size, True) + x = np.linspace(x_min, x_max, g.size[0,0]) + y = np.linspace(y_min, y_max, g.size[0,1]) + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def target_mollifier(g): + x_min = 0. + x_max = 1. + y_min = 0. + y_max = 1. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 0. + x_max = 1. + y_min = 0. + y_max = 1. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + f.f[0][:,:,:,0] = s.toprimitive().q[0][:,:,:,4] + return f + +if __name__ == '__main__': + g = grid([4, 4]) + g.save('TestForcing.xyz') + target_mollifier(g).save('TestForcing.target_mollifier.f') + control_mollifier(g).save('TestForcing.control_mollifier.f') diff --git a/examples/VortexDynamics/config.py b/examples/VortexDynamics/config.py index d85aacc7..6dfffce9 100644 --- a/examples/VortexDynamics/config.py +++ b/examples/VortexDynamics/config.py @@ -165,8 +165,8 @@ def constant_radius_mollifier(g,radius,width): imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], -radius-6.*width, radius+6.*width) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], radius-6.*width, radius+6.*width) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def target_mollifier(g): @@ -185,8 +185,8 @@ def target_mollifier(g): g.xyz[0][:,j,0,0], x_min, x_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -205,8 +205,8 @@ def control_mollifier(g): g.xyz[0][i,:,0,1], y_min, y_max) imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( - 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/VortexDynamics/config.py2 b/examples/VortexDynamics/config.py2 new file mode 100644 index 00000000..d85aacc7 --- /dev/null +++ b/examples/VortexDynamics/config.py2 @@ -0,0 +1,226 @@ +#!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def grid(Nx, L, grid_ratio, length_ratio, offset_ratio): + # Nx: number of grid points in one direction + # L: half length of domain in one direction + # grid_ratio: ratio of grid sizes in far-field(dx1) to near-field(dx2) + # length_ratio: ratio of domain length of near-field(L2) to 2*L + # offset_ratio: ratio of offset length to 2*L + + a, b, c = grid_ratio, offset_ratio, length_ratio + + dx2 = ( 1. + 2.*b*(a - 1.)/(a + 1.) + c*(a - 1.) ) / a + dx1 = a * dx2 + dxi = 2. * b / (dx1 + dx2) + xin = c / dx2 + + inc = 1./(Nx-1) + xi = ( np.arange(Nx-1) + 0.5 ) * inc + xi1 = 0.5 - 0.5 * xin - dxi + xi2 = 0.5 - 0.5 * xin + xi3 = 0.5 + 0.5 * xin + xi4 = 0.5 + 0.5 * xin + dxi + cond1 = np.where(xi<=xi1) + cond2 = np.where((xi>=xi1) & (xi<=xi2) == True) + cond3 = np.where((xi>=xi2) & (xi<=xi3) == True) + cond4 = np.where((xi>=xi3) & (xi<=xi4) == True) + cond5 = np.where(xi>=xi4) + + dx = np.zeros_like(xi) + dx[cond1] = dx1 + dx[cond2] = dx1 - (dx1-dx2) / dxi * ( xi[cond2] - 0.5 + 0.5 * xin + dxi ) + dx[cond3] = dx2 + dx[cond4] = dx1 + (dx1-dx2) / dxi * ( xi[cond4] - 0.5 - 0.5 * xin - dxi ) + dx[cond5] = dx1 + dx *= inc + + x = np.zeros((Nx,),dtype=np.double) + for k, dxk in enumerate(dx): + x[k+1] = x[k] + dxk + + x /= x[-1] + x = L * ( 2. * x - 1. ) + y = x + g = p3d.Grid().set_size([Nx,Nx], True) + + # N2 = int(np.ceil( grid_ratio/( grid_ratio - 1. + 1./length_ratio )*Nx )) + # N1 = Nx - N2 + # dx1, dx2 = (1.-length_ratio)*L/N1, length_ratio*L/N2 + # x = np.zeros([2*(N1+N2)+1,],dtype=np.double) + # x[:N1] = - L + dx1 * np.arange(N1) + # x[-N1:] = L - dx1 * np.arange(N1) + # x[-(N1+N2):-N1] = dx2 + dx2 * np.arange(N2) + # x[N1:(N1+N2)] = - dx2 * N2 + dx2 * np.arange(N2) + # y = x + # g = p3d.Grid().set_size([2*(N1+N2)+1,2*(N1+N2)+1], True) + + # xi = np.linspace(0.,1., g.size[0,0]) + # zeta = np.linspace(0.,1., g.size[0,1]) + # + # offset1, offset2 = 0.15, 0.85 + # width = 0.02 + # + # x = 2.*L* mapping(xi, offset1, offset2, width) - L + # y = 2.*L* mapping(zeta, offset1, offset2, width) - L + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def mapping(xi, offset1, offset2, width): + c0 = width * np.log(np.cosh(offset2/width)/np.cosh(offset1/width)) + return xi + 2.39 * ( width * np.log( np.cosh((xi-offset2)/width)/np.cosh((xi-offset1)/width) ) - c0 + 2. * c0 * xi ) + +def initial_and_target_condition(g, R=1.0/0.15, Ma=0.56, + Pr=0.7, gamma=1.4): + from numpy.matlib import repmat + from scipy.sparse import spdiags, kron, eye, csr_matrix + from scipy.sparse.linalg import spsolve + + n = g.get_size(0)[0] + + xg, yg = g.xyz[0][:,:,0,0], g.xyz[0][:,:,0,1] + src_tensor = np.zeros([n,n,4],dtype=np.double) + vx = np.zeros([n,n],dtype=np.double) + vy = np.zeros([n,n],dtype=np.double) + src = np.zeros([n,n],dtype=np.double) + + eps = 0.0e-16 + loci = [[0.,R],[0.,-R]] + for location in loci: + radius = np.sqrt( (xg-location[0])**2 + (yg-location[1])**2 ) + vt = 1.428 * Ma / (radius+eps) * ( 1. - np.exp(-1.25*(radius**2)) ) + + cosine, sine = (xg-location[0])/(radius+eps), (yg-location[1])/(radius+eps) + vx += -vt * sine + vy += vt * cosine + + dvtdr = 3.57 * Ma * np.exp(-1.25*radius**2) - 1.428/(radius**2) * Ma * ( 1. - np.exp(-1.25*radius**2) ) + src_tensor[:,:,0] -= ( dvtdr * cosine * sine - vt * cosine * sine / radius ) # v_x,x + src_tensor[:,:,1] -= ( dvtdr * sine * sine + vt * cosine * cosine / radius ) # v_x,y + src_tensor[:,:,2] += ( dvtdr * cosine * cosine + vt * sine * sine / radius ) # v_y,x + src_tensor[:,:,3] += ( dvtdr * sine * cosine - vt * cosine * sine / radius ) # v_y,y + + src = - (gamma-1.)/gamma * ( src_tensor[:,:,0]**2 \ + + 2. * src_tensor[:,:,1] * src_tensor[:,:,2] \ + + src_tensor[:,:,3]**2 ) + + # xg.T.tofile('xg.dat') + # yg.T.tofile('yg.dat') + # src.T.tofile('src.dat') + + dA = np.zeros([n,n],dtype=np.double) + dA.fill(1.) + dA[0,:] *= 0.5 * ( xg[1,:] - xg[0,:] ) + dA[-1,:] *= 0.5 * ( xg[-1,:] - xg[-2,:] ) + dA[1:-1,:] *= 0.5 * ( xg[2::,:] - xg[:-2,:] ) + dA[:,0] *= 0.5 * ( yg[:,1] - yg[:,0] ) + dA[:,-1] *= 0.5 * ( yg[:,-1] - yg[:,-2] ) + dA[:,1:-1] *= 0.5 * ( yg[:,2::] - yg[:,:-2] ) + + from joblib import Parallel, delayed + pOverRho = Parallel(n_jobs=36*8)(delayed(poisson_greens_function)(xg,yg,src,dA,xs,ys) \ + for xs, ys in zip(np.nditer(xg),np.nditer(yg))) + pOverRho = np.reshape(pOverRho,[n,n]).T + 1./gamma + + p0 = ( gamma**(1./gamma) * pOverRho )**(gamma/(gamma-1.)) + rho0 = ( gamma * p0 )**(1./gamma) + + s = p3d.Solution().copy_from(g).quiescent(gamma) + t = p3d.Solution().copy_from(g).quiescent(gamma) + for i, xyz in enumerate(g.xyz): + s.q[i][:,:,0,0] = rho0 + # s.q[i][:,:,0,0] = 1.0 + s.q[i][:,:,0,1] = vx + s.q[i][:,:,0,2] = vy + s.q[i][:,:,0,4] = p0 + # s.q[i][:,:,0,4] = 1.0/gamma + + t.q[i][:,:,0,0] = rho0 + # t.q[i][:,:,0,0] = 1.0 + t.q[i][:,:,0,1] = 0. + t.q[i][:,:,0,2] = 0. + t.q[i][:,:,0,4] = p0 + # s.q[i][:,:,0,4] = 1.0/gamma + return s.fromprimitive(gamma), t.fromprimitive(gamma) + +def poisson_greens_function(xg,yg,src,dA,xs,ys): + # xg, yg: global grid coordinates + # src: source global + # dA: global area element + # xs, ys: local position of solution + # return: local value of solution + + rs = np.sqrt( (xg-xs)**2 + (yg-ys)**2 ) + idx = np.where(rs!=0.) + + return np.sum( src[idx] * dA[idx] / 2. / np.pi * np.log(rs[idx]) ) + +def constant_radius_mollifier(g,radius,width): + r = np.sqrt( g.xyz[0][:,:,0,0]**2 + g.xyz[0][:,:,0,1]**2 ) + + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + f.f[0][:,:,0,0] *= 1./np.sqrt(2.*np.pi)/width * np.exp( -(r-radius)**2/2./width/width ) + + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], -radius-6.*width, radius+6.*width) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], radius-6.*width, radius+6.*width) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def target_mollifier(g): + x_min = -1. + x_max = 1. + y_min = -10. + y_max = 10. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.tanh_support( + g.xyz[0][i,:,0,1], y_min, y_max, 40., 0.2) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 5. + y_min = -2. + y_max = 2. + f = p3d.Function().copy_from(g) + f.f[0].fill(1.) + n = f.get_size(0) + for j in range(n[1]): + f.f[0][:,j,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][:,j,0,0], x_min, x_max) + for i in range(n[0]): + f.f[0][i,:,0,0] *= p3d.cubic_bspline_support( + g.xyz[0][i,:,0,1], y_min, y_max) + imin, imax = p3d.find_extents(g.xyz[0][:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(g.xyz[0][0,:,0,1], y_min, y_max) + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', 1, 0, imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + f.f[0][:,:,:,0] = s.toprimitive().q[0][:,:,:,4] + return f + +if __name__ == '__main__': + R = 1.0/0.15 + g = grid(429, 115.*R, 100., 0.03, 0.2) + # g = grid([429, 429], 115.*R) + g.save('VortexDynamics.xyz') + s, t = initial_and_target_condition(g) + s.save('VortexDynamics.ic.q') + t.save('VortexDynamics.target.q') + constant_radius_mollifier(g,0.5*52.5*R,0.1*R).save('AcousticMonopole.target_mollifier.f') + # control_mollifier(g).save('AcousticMonopole.control_mollifier.f') diff --git a/examples/WeiFreundSDML/config.py b/examples/WeiFreundSDML/config.py index 30132591..cb27b09b 100644 --- a/examples/WeiFreundSDML/config.py +++ b/examples/WeiFreundSDML/config.py @@ -58,9 +58,9 @@ def target_mollifier(g): imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) if imin and imax and jmin and jmax: - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'targetRegion', 'COST_TARGET', i + 1, 0, - imin, imax, jmin, jmax, 1, -1) + imin, imax, jmin, jmax, 1, -1)) return f def control_mollifier(g): @@ -76,9 +76,9 @@ def control_mollifier(g): imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) if imin and imax and jmin and jmax: - print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + print((' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( 'controlRegion', 'ACTUATOR', i + 1, 0, - imin, imax, jmin, jmax, 1, -1) + imin, imax, jmin, jmax, 1, -1)) return f def mean_pressure(s): diff --git a/examples/WeiFreundSDML/config.py2 b/examples/WeiFreundSDML/config.py2 new file mode 100644 index 00000000..30132591 --- /dev/null +++ b/examples/WeiFreundSDML/config.py2 @@ -0,0 +1,99 @@ +#ini!/usr/bin/env python +import numpy as np +import plot3dnasa as p3d + +def mapping_function(s, b, c, sigma): + from scipy.special import erf + return ((s - 0.5) * (1.0 + 2.0 * b) - b * sigma * + (np.exp(- ((s - 0.5 + c) / sigma) ** 2) / np.sqrt(np.pi) + + ((s - 0.5 + c) / sigma) * erf((s - 0.5 + c) / sigma) - + np.exp(- ((s - 0.5 - c) / sigma) ** 2) / np.sqrt(np.pi) - + ((s - 0.5 - c) / sigma) * erf((s - 0.5 - c) / sigma))) / \ + (0.5 + b - b * sigma * (np.exp(- ((0.5 + c) / sigma) ** 2) / + np.sqrt(np.pi) + ((0.5 + c) / sigma) * + erf((0.5 + c) / sigma) - + np.exp(- ((0.5 - c) / sigma) ** 2) / + np.sqrt(np.pi) - ((0.5 - c) / sigma) * + erf((0.5 - c) / sigma))) + +def grid(size): + x_min = -60. + x_max = 160. + y_min = -100. + y_max = 100. + g = p3d.Grid().set_size(size, True) + x = x_min + 0.5 * (x_max - x_min) * (1. + mapping_function( + np.linspace(0., 1., g.size[0,0]), 80., 0.58, 0.07)) + y = y_min + 0.5 * (y_max - y_min) * (1. + mapping_function( + np.linspace(0., 1., g.size[0,1]), 20., 0.62, 0.2)) + g.xyz[0][:,:,0,:2] = np.transpose(np.meshgrid(x, y)) + return g + +def target_state(g, u1, u2, S, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i, xyz in enumerate(g.xyz): + x = xyz[:,:,:,0] + s.q[i][:,:,:,1] = u2 + 0.5 * (u1 - u2) * ( + 1. + np.tanh(2. * xyz[:,:,:,1] / \ + (1. + S * np.where(x > 0., x, np.zeros_like(x))))) + return s.fromprimitive(gamma) + +def initial_condition(g, u1, u2, gamma=1.4): + s = p3d.Solution().copy_from(g).quiescent(gamma) + for i, xyz in enumerate(g.xyz): + s.q[i][:,:,:,1] = u2 + 0.5 * (u1 - u2) * ( + 1. + np.tanh(2. * xyz[:,:,:,1])) + return s.fromprimitive(gamma) + +def target_mollifier(g): + x_min = 0. + x_max = 100. + y_min = -74. + y_max = -66. + f = p3d.Function().copy_from(g) + for i, xyz in enumerate(g.xyz): + f.f[i][:,:,:,0] = p3d.tanh_support(xyz[:,:,:,0], x_min, x_max, + 80., 0.14) * \ + p3d.cubic_bspline_support(xyz[:,:,:,1], y_min, y_max) + imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) + if imin and imax and jmin and jmax: + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'targetRegion', 'COST_TARGET', i + 1, 0, + imin, imax, jmin, jmax, 1, -1) + return f + +def control_mollifier(g): + x_min = 1. + x_max = 7. + y_min = -3. + y_max = 3. + f = p3d.Function().copy_from(g) + for i, xyz in enumerate(g.xyz): + f.f[i][:,:,:,0] = p3d.tanh_support( + xyz[:,:,:,0], x_min, x_max, 20., 0.8) * p3d.tanh_support( + xyz[:,:,:,1], y_min, y_max, 20., 0.8) + imin, imax = p3d.find_extents(xyz[:,0,0,0], x_min, x_max) + jmin, jmax = p3d.find_extents(xyz[0,:,0,1], y_min, y_max) + if imin and imax and jmin and jmax: + print (' {:<20} {:<21} {:>4d} {:>7d}' + 6 * ' {:>4d}').format( + 'controlRegion', 'ACTUATOR', i + 1, 0, + imin, imax, jmin, jmax, 1, -1) + return f + +def mean_pressure(s): + f = p3d.Function().copy_from(s) + s = s.toprimitive() + for i, q in enumerate(s.q): + f.f[i][:,:,:,0] = q[:,:,:,4] + return f + +if __name__ == '__main__': + g = grid([961, 641]) + g.save('WeiFreundSDML.xyz') + s = initial_condition(g, u1=0.9, u2=0.2) + s.save('WeiFreundSDML.ic.q') + target_state(g, u1=0.9, u2=0.2, S=0.05).save('WeiFreundSDML.target.q') + target_mollifier(g).save('WeiFreundSDML.target_mollifier.f') + control_mollifier(g).save('WeiFreundSDML.control_mollifier.f') + mean_pressure(s).save('WeiFreundSDML.mean_pressure.f')