def test_vectorized_all_derivs(self): xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) ycp = np.array([[5.0, 12.0, 14.0, 16.0, 21.0, 29.0], [7.0, 13.0, 9.0, 6.0, 12.0, 14.0]]) n = 12 x = np.linspace(1.0, 12.0, n) for method in SPLINE_METHODS: prob = om.Problem() # These methods have their own test. if method in ['akima', 'bsplines']: continue opts = {} comp = om.SplineComp(method=method, vec_size=2, x_cp_val=xcp, x_interp_val=x, interp_options=opts) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=ycp) prob.model.add_subsystem('interp1', comp) prob.setup(force_alloc_complex=True) prob.run_model() if method.startswith('scipy'): derivs = prob.check_partials(out_stream=None) assert_check_partials(derivs, atol=1e-7, rtol=1e-7) else: derivs = prob.check_partials(out_stream=None, method='cs') assert_check_partials(derivs, atol=1e-12, rtol=1e-12)
def test_vectorized_akima(self): xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) ycp = np.array([[5.0, 12.0, 14.0, 16.0, 21.0, 29.0], [7.0, 13.0, 9.0, 6.0, 12.0, 14.0]]) n = 12 x = np.linspace(1.0, 12.0, n) comp = om.SplineComp(method='akima', vec_size=2, x_cp_val=xcp, x_interp_val=x, interp_options={'delta_x': 0.1}) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=ycp) self.prob.model.add_subsystem('akima1', comp) self.prob.setup(force_alloc_complex=True) self.prob.run_model() y = np.array([[ 5., 12., 13.01239669, 14., 14.99888393, 16., 17.06891741, 18.26264881, 19.5750558, 21., 24.026042, 29. ], [ 7., 13., 11.02673797, 9., 7.09090909, 6., 6.73660714, 8.46428571, 10.45982143, 12., 13.08035714, 14. ]]) assert_near_equal(y.flatten(), self.prob['akima1.y_val'].flatten(), tolerance=1e-8) derivs = self.prob.check_partials(out_stream=None, method='cs') assert_check_partials(derivs, atol=1e-14, rtol=1e-14)
def test(self): surface = get_default_surfaces()[0] surface['with_wave'] = True surface['t_over_c_cp'] = np.array([0.15, 0.21, 0.03, 0.05]) nx = surface['mesh'].shape[0] ny = surface['mesh'].shape[1] n_cp = len(surface['t_over_c_cp']) group = om.Group() indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) indep_var_comp.add_output('Mach_number', val=.95) indep_var_comp.add_output('CL', val=0.7) indep_var_comp.add_output('widths', val = np.array([12.14757848, 11.91832712, 11.43730892]),units='m') indep_var_comp.add_output('cos_sweep', val = np.array([10.01555924, 9.80832351, 9.79003729]),units='m') indep_var_comp.add_output('chords', val = np.array([ 2.72835132, 5.12528179, 7.88916016, 13.6189974]),units='m') group.add_subsystem('indep_var_comp', indep_var_comp, promotes=['*']) x_interp = np.linspace(0., 1., int(ny-1)) comp = group.add_subsystem('t_over_c_bsp', om.SplineComp( method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order' : min(n_cp, 4)}), promotes_inputs=['t_over_c_cp'], promotes_outputs=['t_over_c']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c') comp = WaveDrag(surface=surface) group.add_subsystem('wavedrag', comp, promotes=['*']) run_test(self, group, complex_flag=True)
def test(self): surface = get_default_surfaces()[0] surface['t_over_c_cp'] = np.array([0.1, 0.15, 0.2]) nx = surface['mesh'].shape[0] ny = surface['mesh'].shape[1] n_cp = len(surface['t_over_c_cp']) group = om.Group() indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) group.add_subsystem('indep_var_comp', indep_var_comp, promotes=['*']) x_interp = np.linspace(0., 1., int(ny - 1)) comp = group.add_subsystem('t_over_c_bsp', om.SplineComp( method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['t_over_c_cp'], promotes_outputs=['t_over_c']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c', y_cp_val=np.zeros(n_cp)) comp = ViscousDrag(surface=surface, with_viscous=True) group.add_subsystem('viscousdrag', comp, promotes=['*']) run_test(self, group, complex_flag=True)
def test_2to3doc_fixed_grid(self): ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) ncp = len(ycp) n = 11 prob = om.Problem() akima_option = {'delta_x': 0.1} comp = om.SplineComp(method='akima', num_cp=ncp, x_interp_val=np.linspace(0.0, 1.0, n), interp_options=akima_option) prob.model.add_subsystem('comp1', comp) comp.add_spline(y_cp_name='chord_cp', y_interp_name='chord', y_cp_val=ycp) prob.setup() prob.run_model() y = np.array([[ 5., 9.4362525, 12., 13.0012475, 14., 14.99875415, 16., 17.93874585, 21., 24.625, 29. ]]) assert_near_equal(prob['comp1.chord'], y, 1e-6)
def test_y_units(self): x_cp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) n = 50 x = np.linspace(1.0, 12.0, n) prob = om.Problem() model = prob.model # Set options specific to akima akima_option = {'delta_x': 0.1, 'eps': 1e-30} comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x, interp_options=akima_option) prob.model.add_subsystem('atmosphere', comp) comp.add_spline(y_cp_name='alt_cp', y_interp_name='alt', y_cp_val=y_cp, y_units='kft') prob.setup(force_alloc_complex=True) prob.run_model() output = prob.model.list_inputs(units=True) self.assertEqual(output[0][1]['units'], 'kft')
def test_akima_options(self): import numpy as np import openmdao.api as om x_cp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) n = 50 x = np.linspace(1.0, 12.0, n) prob = om.Problem() model = prob.model # Set options specific to akima akima_option = {'delta_x': 0.1, 'eps': 1e-30} comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x, interp_options=akima_option) prob.model.add_subsystem('atmosphere', comp) comp.add_spline(y_cp_name='alt_cp', y_interp_name='alt', y_cp_val=y_cp, y_units='kft') prob.setup(force_alloc_complex=True) prob.run_model()
def test_bspline_options(self): import numpy as np import openmdao.api as om prob = om.Problem() model = prob.model n_cp = 80 n_point = 160 t = np.linspace(0, 3.0*np.pi, n_cp) tt = np.linspace(0, 3.0*np.pi, n_point) x = np.sin(t) model.add_subsystem('px', om.IndepVarComp('x', val=x)) # Set options specific to bsplines bspline_options = {'order': 3} comp = om.SplineComp(method='bsplines', x_interp_val=tt, num_cp=n_cp, interp_options=bspline_options) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units=None) model.connect('px.x', 'interp.h_cp') prob.setup(force_alloc_complex=True) prob.run_model()
def test_spline_distribution_example(self): import numpy as np import openmdao.api as om from openmdao.utils.spline_distributions import sine_distribution x_cp = np.linspace(0., 1., 6) y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) n = 20 x = om.sine_distribution(20, start=0, end=1, phase=np.pi) prob = om.Problem() comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x) prob.model.add_subsystem('akima1', comp) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=y_cp) prob.setup(force_alloc_complex=True) prob.run_model() akima_y = np.array([[5. , 5.32381994, 6.28062691 , 7.79410646 , 9.64169506, 11.35166363, 12.26525921, 12.99152288, 13.77257256, 14.58710327, 15.41289673, 16.28341046, 17.96032258, 20.14140712, 22.31181718, 24.40891577, 26.27368825, 27.74068235, 28.67782484, 29. ]]) assert_rel_error(self, akima_y.flatten(), prob['akima1.y_val'].flatten(), tolerance=1e-8)
def test_bsplines_vectorized(self): prob = om.Problem() model = prob.model n_cp = 5 n_point = 10 t = np.linspace(0, 0.5 * np.pi, n_cp) tt = np.linspace(0, 0.5 * np.pi, n_point) x = np.empty((2, n_cp)) x[0, :] = np.sin(t) x[1, :] = 2.0 * np.sin(t) t_sin = (0.5 * (1.0 + np.sin(-0.5 * np.pi + 2.0 * tt))) * np.pi * 0.5 model.add_subsystem('px', om.IndepVarComp('x', val=x)) bspline_options = {'order': 4} comp = om.SplineComp(method='bsplines', x_interp_val=t_sin, num_cp=n_cp, vec_size=2, interp_options=bspline_options) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') model.connect('px.x', 'interp.h_cp') prob.setup(force_alloc_complex=True) prob.run_model() xx = prob['interp.h'] with printoptions(precision=3, floatmode='fixed'): assert_near_equal( x[0, :], np.array([0., 0.38268343, 0.70710678, 0.92387953, 1.]), 1e-5) assert_near_equal( x[1, :], 2.0 * np.array([0., 0.38268343, 0.70710678, 0.92387953, 1.]), 1e-5) assert_near_equal( xx[0, :], np.array([ 0., 0.06687281, 0.23486869, 0.43286622, 0.6062628, 0.74821484, 0.86228902, 0.94134389, 0.98587725, 1. ]), 1e-5) assert_near_equal( xx[1, :], 2.0 * np.array([ 0., 0.06687281, 0.23486869, 0.43286622, 0.6062628, 0.74821484, 0.86228902, 0.94134389, 0.98587725, 1. ]), 1e-5) derivs = prob.check_partials(out_stream=None, method='cs') assert_check_partials(derivs, atol=1e-14, rtol=1e-14)
def test_basic_example(self): import numpy as np import openmdao.api as om xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) n = 50 x = np.linspace(1.0, 12.0, n) prob = om.Problem() akima_option = {'delta_x': 0.1} comp = om.SplineComp(method='akima', x_cp_val=xcp, x_interp_val=x, interp_options=akima_option) prob.model.add_subsystem('akima1', comp) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=ycp) prob.setup(force_alloc_complex=True) prob.run_model() akima_y = np.array([[ 5. , 7.20902005, 9.21276849, 10.81097162, 11.80335574, 12.1278001 , 12.35869145, 12.58588536, 12.81022332, 13.03254681, 13.25369732, 13.47451633, 13.69584534, 13.91852582, 14.14281484, 14.36710105, 14.59128625, 14.81544619, 15.03965664, 15.26399335, 15.48853209, 15.7133486 , 15.93851866, 16.16573502, 16.39927111, 16.63928669, 16.8857123 , 17.1384785 , 17.39751585, 17.66275489, 17.93412619, 18.21156029, 18.49498776, 18.78433915, 19.07954501, 19.38053589, 19.68724235, 19.99959495, 20.31752423, 20.64096076, 20.96983509, 21.37579297, 21.94811407, 22.66809748, 23.51629844, 24.47327219, 25.51957398, 26.63575905, 27.80238264, 29. ]]) assert_rel_error(self, akima_y.flatten(), prob['akima1.y_val'].flatten(), tolerance=1e-8)
def test_multi_splines(self): import numpy as np import openmdao.api as om x_cp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0]) y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) y_cp2 = np.array([1.0, 5.0, 7.0, 8.0, 13.0, 16.0]) n = 50 x = np.linspace(1.0, 12.0, n) prob = om.Problem() comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x) prob.model.add_subsystem('akima1', comp) comp.add_spline(y_cp_name='ycp1', y_interp_name='y_val1', y_cp_val=y_cp) comp.add_spline(y_cp_name='ycp2', y_interp_name='y_val2', y_cp_val=y_cp2) prob.setup(force_alloc_complex=True) prob.run_model()
def test_akima_backward_compatibility(self): comp = om.SplineComp(method='akima', x_cp_val=self.x_cp, x_interp_val=self.x, interp_options={'delta_x': 0.1}) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=self.y_cp) self.prob.model.add_subsystem('akima1', comp) self.prob.setup(force_alloc_complex=True) self.prob.run_model() # Verification array from openmdao 2.x using AkimaSplineComp akima_y = np.array([[ 5., 7.20902005, 9.21276849, 10.81097162, 11.80335574, 12.1278001, 12.35869145, 12.58588536, 12.81022332, 13.03254681, 13.25369732, 13.47451633, 13.69584534, 13.91852582, 14.14281484, 14.36710105, 14.59128625, 14.81544619, 15.03965664, 15.26399335, 15.48853209, 15.7133486, 15.93851866, 16.16573502, 16.39927111, 16.63928669, 16.8857123, 17.1384785, 17.39751585, 17.66275489, 17.93412619, 18.21156029, 18.49498776, 18.78433915, 19.07954501, 19.38053589, 19.68724235, 19.99959495, 20.31752423, 20.64096076, 20.96983509, 21.37579297, 21.94811407, 22.66809748, 23.51629844, 24.47327219, 25.51957398, 26.63575905, 27.80238264, 29. ]]) assert_near_equal(akima_y.flatten(), self.prob['akima1.y_val'].flatten(), tolerance=1e-8) derivs = self.prob.check_partials(out_stream=None, method='cs') assert_check_partials(derivs, atol=1e-14, rtol=1e-14)
def test_spline_distribution_example(self): x_cp = np.linspace(0., 1., 6) y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0]) n = 20 x = sine_distribution(n, start=0.0, end=1.0, phase=np.pi) prob = om.Problem() comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x) prob.model.add_subsystem('akima1', comp) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=y_cp) prob.setup(force_alloc_complex=True) prob.run_model() assert_array_almost_equal( prob['akima1.y_val'], np.array([[ 5., 5.32381994, 6.28062691, 7.79410646, 9.64169506, 11.35166363, 12.26525921, 12.99152288, 13.77257256, 14.58710327, 15.41289673, 16.28341046, 17.96032258, 20.14140712, 22.31181718, 24.40891577, 26.27368825, 27.74068235, 28.67782484, 29. ]]))
def test_no_ycp_val(self): comp = om.SplineComp(method='akima', x_cp_val=self.x_cp, x_interp_val=self.x) comp.add_spline(y_cp_name='ycp', y_interp_name='y_val') self.prob.model.add_subsystem('akima1', comp) self.prob.setup(force_alloc_complex=True) self.prob.run_model()
def test_bsplines_2to3doc(self): from openmdao.utils.spline_distributions import sine_distribution prob = om.Problem() model = prob.model n_cp = 5 n_point = 10 t = np.linspace(0, 0.5 * np.pi, n_cp) x = np.empty((2, n_cp)) x[0, :] = np.sin(t) x[1, :] = 2.0 * np.sin(t) # In 2.x, the BsplinesComp had a built-in sinusoidal distribution. t_sin = sine_distribution(n_point) * np.pi * 0.5 bspline_options = {'order': 4} comp = om.SplineComp(method='bsplines', x_interp_val=t_sin, num_cp=n_cp, vec_size=2, interp_options=bspline_options) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') prob.setup() prob.run_model() xx = prob['interp.h'] with printoptions(precision=3, floatmode='fixed'): assert_near_equal( x[0, :], np.array([0., 0.38268343, 0.70710678, 0.92387953, 1.]), 1e-5) assert_near_equal( x[1, :], 2.0 * np.array([0., 0.38268343, 0.70710678, 0.92387953, 1.]), 1e-5) assert_near_equal( xx[0, :], np.array([ 0., 0.06687281, 0.23486869, 0.43286622, 0.6062628, 0.74821484, 0.86228902, 0.94134389, 0.98587725, 1. ]), 1e-5) assert_near_equal( xx[1, :], 2.0 * np.array([ 0., 0.06687281, 0.23486869, 0.43286622, 0.6062628, 0.74821484, 0.86228902, 0.94134389, 0.98587725, 1. ]), 1e-5)
def test_multiple_splines(self): comp = om.SplineComp(method='akima', x_cp_val=self.x_cp, x_interp_val=self.x) self.prob.model.add_subsystem('akima1', comp) comp.add_spline(y_cp_name='ycp1', y_interp_name='y_val1', y_cp_val=self.y_cp) comp.add_spline(y_cp_name='ycp2', y_interp_name='y_val2', y_cp_val=self.y_cp2) self.prob.setup(force_alloc_complex=True) self.prob.run_model()
def test_akima_interp_options(self): akima_option = {'delta_x': 0.1, 'eps': 1e-30} comp = om.SplineComp(method='akima', x_cp_val=self.x_cp, x_interp_val=self.x, interp_options=akima_option) self.prob.model.add_subsystem('atmosphere', comp) comp.add_spline(y_cp_name='alt_cp', y_interp_name='alt', y_cp_val=self.y_cp, y_units='kft') self.prob.setup(force_alloc_complex=True) self.prob.run_model()
def test_bspline_interp_basic(self): prob = om.Problem() model = prob.model n_cp = 80 n_point = 160 t = np.linspace(0, 3.0 * np.pi, n_cp) tt = np.linspace(0, 3.0 * np.pi, n_point) x = np.sin(t) model.add_subsystem('px', om.IndepVarComp('x', val=x)) bspline_options = {'order': 4} comp = om.SplineComp(method='bsplines', x_interp_val=tt, num_cp=n_cp, interp_options=bspline_options) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') model.connect('px.x', 'interp.h_cp') prob.setup(force_alloc_complex=True) prob.run_model() xx = prob['interp.h'].flatten() tt = np.linspace(0, 3.0 * np.pi, n_point) x_expected = np.sin(tt) delta = xx - x_expected # Here we test that we don't have crazy interpolation error. self.assertLess(max(delta), .15) # And that it gets middle points a little better. self.assertLess(max(delta[15:-15]), .06) derivs = prob.check_partials(out_stream=None, method='cs') assert_check_partials(derivs, atol=1e-14, rtol=1e-14)
def test_bspline_bug(self): # Tests a bug fix where the interp_options weren't passed into # the bspline interp comp bspline_options = {'order': 3} comp = om.SplineComp(method='bsplines', num_cp=6, x_interp_val=self.x, interp_options=bspline_options) self.prob.model.add_subsystem('atmosphere', comp) comp.add_spline(y_cp_name='alt_cp', y_interp_name='alt', y_cp_val=self.y_cp, y_units='kft') self.prob.setup(force_alloc_complex=True) # If we set the bspline order to 3, then k should internally be 4 self.assertEqual(comp.interps['alt'].table.k, 4)
def test_small_akima_spline_bug(self): # Fixes a bug that only occure for a 4 point spline. prob = om.Problem() num_cp = 4 num_radial = 11 comp = om.IndepVarComp() comp.add_output("chord_cp", units="m", val=np.array([0.1, 0.2, 0.3, 0.15])) comp.add_output("theta_cp", units="rad", val=np.array([1.0, 0.8, 0.6, 0.4])) prob.model.add_subsystem("inputs_comp", comp, promotes=["*"]) x_cp = np.linspace(0.0, 1.0, num_cp) x_interp = cell_centered(num_radial, start=0.0, end=1.0) akima_options = {'delta_x': 0.1} comp = om.SplineComp(method='akima', interp_options=akima_options, x_cp_val=x_cp, x_interp_val=x_interp) comp.add_spline(y_cp_name='chord_cp', y_interp_name='chord_interp', y_units='m') comp.add_spline(y_cp_name='theta_cp', y_interp_name='theta_interp', y_units='rad') prob.model.add_subsystem( 'akima_comp', comp, promotes_inputs=['chord_cp', 'theta_cp'], promotes_outputs=['chord_interp', 'theta_interp']) prob.setup() # Make sure we don't get an exception prob.run_model()
def setup(self): nx = int(self.options["num_x"]) ny = int(self.options["num_y"]) n_twist = int(self.options["num_twist"]) # ================================================================= # Set up mesh # ================================================================= self.add_subsystem( "mesh", PlanformMesh(num_x=nx, num_y=ny), promotes_inputs=[ ("S", "ac|geom|wing|S_ref"), ("AR", "ac|geom|wing|AR"), ("taper", "ac|geom|wing|taper"), ("sweep", "ac|geom|wing|c4sweep"), ], ) # Add bspline component for twist x_interp = np.linspace(0.0, 1.0, ny) comp = self.add_subsystem( "twist_bsp", om.SplineComp(method="bsplines", x_interp_val=x_interp, num_cp=n_twist, interp_options={"order": min(n_twist, 4)}), promotes_inputs=[("twist_cp", "ac|geom|wing|twist")], ) comp.add_spline(y_cp_name="twist_cp", y_interp_name="twist", y_units="deg") # Apply twist spline to mesh self.add_subsystem( "twist_mesh", Rotate(val=np.zeros(ny), mesh_shape=(nx, ny, 3), symmetry=True)) self.connect("twist_bsp.twist", "twist_mesh.twist") self.connect("mesh.mesh", "twist_mesh.in_mesh") # ================================================================= # Compute atmospheric and fluid properties # ================================================================= self.add_subsystem( "temp", TemperatureComp(num_nodes=1), promotes_inputs=["fltcond|h", "fltcond|TempIncrement"]) self.add_subsystem("pressure", PressureComp(num_nodes=1), promotes_inputs=["fltcond|h"]) self.add_subsystem("density", DensityComp(num_nodes=1)) self.connect("temp.fltcond|T", "density.fltcond|T") self.connect("pressure.fltcond|p", "density.fltcond|p") self.add_subsystem("sound_speed", SpeedOfSoundComp(num_nodes=1)) self.connect("temp.fltcond|T", "sound_speed.fltcond|T") self.add_subsystem( "airspeed", om.ExecComp("Utrue = Mach * a", Utrue={ "units": "m/s", "val": 200.0 }, a={ "units": "m/s", "val": 300.0 }), promotes_inputs=[("Mach", "fltcond|M")], ) self.connect("sound_speed.fltcond|a", "airspeed.a") # Compute dimensionalized Reynolds number (use linear interpolation from standard atmosphere up # to 35k ft to estimate dynamic viscosity) self.add_subsystem( "Re_calc", om.ExecComp( "re = rho * u / (-3.329134*10**(-10) * h + 1.792398*10**(-5))", re={ "units": "1/m", "val": 1e6 }, rho={ "units": "kg/m**3", "val": 1.0 }, u={ "units": "m/s", "val": 100.0 }, h={ "units": "m", "val": 1.0 }, ), promotes_inputs=[("h", "fltcond|h")], ) self.connect("density.fltcond|rho", "Re_calc.rho") self.connect("airspeed.Utrue", "Re_calc.u") # ================================================================= # Call OpenAeroStruct # ================================================================= surf_dict = { "name": "wing", "mesh": np.zeros((nx, ny, 3)), # this must be defined # because the VLMGeometry component uses the shape of the mesh in this # dictionary to determine the size of the mesh; the values don't matter "symmetry": True, # if true, model one half of wing # reflected across the plane y = 0 "S_ref_type": "projected", # how we compute the wing area, # can be 'wetted' or 'projected' # Aerodynamic performance of the lifting surface at # an angle of attack of 0 (alpha=0). # These CL0 and CD0 values are added to the CL and CD # obtained from aerodynamic analysis of the surface to get # the total CL and CD. # These CL0 and CD0 values do not vary wrt alpha. "CL0": 0.0, # CL of the surface at alpha=0 "CD0": 0.0, # CD of the surface at alpha=0 # Airfoil properties for viscous drag calculation "k_lam": 0.05, # percentage of chord with laminar # flow, used for viscous drag "t_over_c": np.array([0.12]), # thickness over chord ratio (NACA SC2-0612) "c_max_t": 0.37, # chordwise location of maximum (NACA SC2-0612) # thickness "with_viscous": True, # if true, compute viscous drag "with_wave": True, # if true, compute wave drag } # Overwrite any options in the surface dict with those provided in the options if self.options["surf_options"] is not None: for key in self.options["surf_options"]: surf_dict[key] = self.options["surf_options"][key] self.add_subsystem( "aero_point", AeroPoint(surfaces=[surf_dict]), promotes_inputs=[("Mach_number", "fltcond|M"), ("alpha", "fltcond|alpha")], promotes_outputs=[ (f"{surf_dict['name']}_perf.CD", "fltcond|CD"), (f"{surf_dict['name']}_perf.CL", "fltcond|CL"), ], ) self.connect( "twist_mesh.mesh", [ f"aero_point.{surf_dict['name']}.def_mesh", f"aero_point.aero_states.{surf_dict['name']}_def_mesh" ], ) self.connect("airspeed.Utrue", "aero_point.v") self.connect("density.fltcond|rho", "aero_point.rho") self.connect("Re_calc.re", "aero_point.re") # Set input defaults for inputs that go to multiple locations self.set_input_defaults("fltcond|M", 0.1) self.set_input_defaults("fltcond|alpha", 0.0) # Set the thickness to chord ratio for wave and viscous drag calculation. # It must have a thickness to chord ratio for each panel, so there must be # ny-1 elements. Allow either one value (and duplicate it ny-1 times) or # an array of length ny-1, but nothing else. # NOTE: for aerostructural cases, this should be a design variable with control points over a spline if isinstance(surf_dict["t_over_c"], (int, float)) or surf_dict["t_over_c"].size == 1: self.set_input_defaults( f"aero_point.{surf_dict['name']}_perf.t_over_c", val=surf_dict["t_over_c"] * np.ones(ny - 1)) elif surf_dict["t_over_c"].size == ny - 1: self.set_input_defaults( f"aero_point.{surf_dict['name']}_perf.t_over_c", val=surf_dict["t_over_c"]) else: raise ValueError( f"t_over_c in the surface dict must be either a number or an ndarray " f"with either one or ny-1 elements, not {surf_dict['t_over_c']}" )
def test3(self): """ This is an extreme nonphysical case (large twist angles) for checking the computation. """ surface = get_default_surfaces()[0] surface['t_over_c_cp'] = np.array([0.1, 0.15, 0.2]) surface['spar_thickness_cp'] = np.array([0.004, 0.008, 0.02]) surface['skin_thickness_cp'] = np.array([0.01, 0.015, 0.021]) surface['fem_chords_cp'] = np.array([2., 3., 4.]) surface['streamwise_chords_cp'] = np.array([3., 4., 5.]) surface['fem_twists_cp'] = np.array([5., 3., 2.]) surface['data_x_upper'] = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') surface['data_x_lower'] = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') surface['data_y_upper'] = np.array([ 0.0447, 0.046, 0.0472, 0.0484, 0.0495, 0.0505, 0.0514, 0.0523, 0.0531, 0.0538, 0.0545, 0.0551, 0.0557, 0.0563, 0.0568, 0.0573, 0.0577, 0.0581, 0.0585, 0.0588, 0.0591, 0.0593, 0.0595, 0.0597, 0.0599, 0.06, 0.0601, 0.0602, 0.0602, 0.0602, 0.0602, 0.0602, 0.0601, 0.06, 0.0599, 0.0598, 0.0596, 0.0594, 0.0592, 0.0589, 0.0586, 0.0583, 0.058, 0.0576, 0.0572, 0.0568, 0.0563, 0.0558, 0.0553, 0.0547, 0.0541 ], dtype='complex128') surface['data_y_lower'] = np.array([ -0.0447, -0.046, -0.0473, -0.0485, -0.0496, -0.0506, -0.0515, -0.0524, -0.0532, -0.054, -0.0547, -0.0554, -0.056, -0.0565, -0.057, -0.0575, -0.0579, -0.0583, -0.0586, -0.0589, -0.0592, -0.0594, -0.0595, -0.0596, -0.0597, -0.0598, -0.0598, -0.0598, -0.0598, -0.0597, -0.0596, -0.0594, -0.0592, -0.0589, -0.0586, -0.0582, -0.0578, -0.0573, -0.0567, -0.0561, -0.0554, -0.0546, -0.0538, -0.0529, -0.0519, -0.0509, -0.0497, -0.0485, -0.0472, -0.0458, -0.0444 ], dtype='complex128') surface['original_wingbox_airfoil_t_over_c'] = 0.1 mesh = surface['mesh'] ny = mesh.shape[1] nx = mesh.shape[0] n_cp = len(surface['t_over_c_cp']) prob = om.Problem() indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) indep_var_comp.add_output('spar_thickness_cp', val=surface['spar_thickness_cp']) indep_var_comp.add_output('skin_thickness_cp', val=surface['skin_thickness_cp']) indep_var_comp.add_output('fem_chords_cp', val=surface['fem_chords_cp']) indep_var_comp.add_output('streamwise_chords_cp', val=surface['streamwise_chords_cp']) indep_var_comp.add_output('fem_twists_cp', val=surface['fem_twists_cp']) prob.model.add_subsystem('indep_var_comp', indep_var_comp, promotes=['*']) x_interp = np.linspace(0., 1., int(ny - 1)) comp = prob.model.add_subsystem( 'bsplines_comp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['*'], promotes_outputs=['*']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c') comp.add_spline(y_cp_name='skin_thickness_cp', y_interp_name='skin_thickness', y_units='m') comp.add_spline(y_cp_name='spar_thickness_cp', y_interp_name='spar_thickness', y_units='m') comp.add_spline(y_cp_name='fem_chords_cp', y_interp_name='fem_chords', y_units='m') comp.add_spline(y_cp_name='streamwise_chords_cp', y_interp_name='streamwise_chords', y_units='m') comp.add_spline(y_cp_name='fem_twists_cp', y_interp_name='fem_twists', y_units='deg') comp = SectionPropertiesWingbox(surface=surface) prob.model.add_subsystem('sec_prop_wb', comp, promotes=['*']) prob.setup() # om.view_model(prob) prob.run_model() # print( prob['A'] ) # print( prob['A_enc'] ) # print( prob['A_int'] ) # print( prob['Iy'] ) # print( prob['Qz'] ) # print( prob['Iz'] ) # print( prob['J'] ) # print( prob['htop'] ) # print( prob['hbottom'] ) # print( prob['hfront'] ) # print( prob['hrear'] ) assert_rel_error(self, prob['A'], np.array([0.0058738, -0.05739528, -0.05042289]), 1e-6) assert_rel_error(self, prob['A_enc'], np.array([0.3243776, 0.978003, 2.17591]), 1e-6) assert_rel_error(self, prob['A_int'], np.array([0.3132502, 0.949491, 2.11512]), 1e-6) assert_rel_error( self, prob['Iy'], np.array([3.59803239e-05, -1.52910019e-02, -4.01035510e-03]), 1e-6) assert_rel_error(self, prob['Qz'], np.array([0.00129261, 0.00870662, 0.02500053]), 1e-6) assert_rel_error(self, prob['Iz'], np.array([0.00056586, -0.00582207, -0.02877714]), 1e-6) assert_rel_error(self, prob['J'], np.array([0.00124939, 0.01241967, 0.06649673]), 1e-6) assert_rel_error(self, prob['htop'], np.array([0.53933652, -0.23509863, 0.71255343]), 1e-6) assert_rel_error(self, prob['hbottom'], np.array([0.50366564, -0.19185349, 0.73525459]), 1e-6) assert_rel_error(self, prob['hfront'], np.array([0.13442747, -0.78514756, -0.3919784]), 1e-6) assert_rel_error(self, prob['hrear'], np.array([0.12219305, -0.71214916, -0.35484131]), 1e-6)
def setup(self): surface = self.options['surface'] ny = surface['mesh'].shape[1] if 'spar_thickness_cp' in surface.keys( ) or 'skin_thickness_cp' in surface.keys(): # Add independent variables that do not belong to a specific component indep_var_comp = om.IndepVarComp() # Add structural components to the surface-specific group self.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) if 'spar_thickness_cp' in surface.keys(): n_cp = len(surface['spar_thickness_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 'spar_thickness_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['spar_thickness_cp'], promotes_outputs=['spar_thickness']) comp.add_spline(y_cp_name='spar_thickness_cp', y_interp_name='spar_thickness') indep_var_comp.add_output('spar_thickness_cp', val=surface['spar_thickness_cp'], units='m') if 'skin_thickness_cp' in surface.keys(): n_cp = len(surface['skin_thickness_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 'skin_thickness_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['skin_thickness_cp'], promotes_outputs=['skin_thickness']) comp.add_spline(y_cp_name='skin_thickness_cp', y_interp_name='skin_thickness') indep_var_comp.add_output('skin_thickness_cp', val=surface['skin_thickness_cp'], units='m') self.add_subsystem( 'wingbox_geometry', WingboxGeometry(surface=surface), promotes_inputs=['mesh'], promotes_outputs=['fem_chords', 'fem_twists', 'streamwise_chords']) self.add_subsystem('wingbox', SectionPropertiesWingbox(surface=surface), promotes_inputs=[ 'spar_thickness', 'skin_thickness', 't_over_c', 'fem_chords', 'fem_twists', 'streamwise_chords' ], promotes_outputs=[ 'A', 'Iy', 'Qz', 'Iz', 'J', 'A_enc', 'A_int', 'htop', 'hbottom', 'hfront', 'hrear' ])
def test_error_messages(self): n_cp = 80 n_point = 160 t = np.linspace(0, 3.0 * np.pi, n_cp) tt = np.linspace(0, 3.0 * np.pi, n_point) x = np.sin(t) prob = om.Problem() comp = om.SplineComp(method='bsplines', x_interp_val=tt, x_cp_val=t) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') with self.assertRaises(ValueError) as cm: prob.setup() msg = "'interp' <class SplineComp>: 'x_cp_val' is not a valid option when using method 'bsplines'. " msg += "Set 'num_cp' instead." self.assertEqual(str(cm.exception), msg) prob = om.Problem() comp = om.SplineComp(method='akima', x_interp_val=tt, num_cp=n_cp, x_cp_val=t) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') with self.assertRaises(ValueError) as cm: prob.setup() msg = "'interp' <class SplineComp>: It is not valid to set both options 'x_cp_val' and 'num_cp'." self.assertEqual(str(cm.exception), msg) prob = om.Problem() comp = om.SplineComp(method='akima', x_interp_val=tt) prob.model.add_subsystem('interp', comp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units='km') with self.assertRaises(ValueError) as cm: prob.setup() msg = "'interp' <class SplineComp>: Either option 'x_cp_val' or 'num_cp' must be set." self.assertEqual(str(cm.exception), msg)
def setup(self): surface = self.options['surface'] connect_geom_DVs = self.options['connect_geom_DVs'] # Get the surface name and create a group to contain components # only for this surface ny = surface['mesh'].shape[1] # Check if any control points were added to the surface dict dv_keys = set([ 'twist_cp', 'chord_cp', 'xshear_cp', 'yshear_cp', 'zshear_cp', 'sweep', 'span', 'taper', 'dihedral', 't_over_c_cp' ]) active_dv_keys = dv_keys.intersection(set(surface.keys())) # Make sure that at least one of them is an independent variable make_ivc = False for key in active_dv_keys: if surface.get(key + '_dv', True): make_ivc = True break if make_ivc or self.options['DVGeo']: # Add independent variables that do not belong to a specific component indep_var_comp = om.IndepVarComp() # If connect_geom_DVs is true, then we promote all of the geometric # design variables to their appropriate manipulation functions. # If it's false, then we do not connect them, and the user can # choose to provide different values to those manipulation functions. # This is useful when you want to have morphing DVs, such as twist # or span, that are different at each point in a multipoint scheme. if connect_geom_DVs: self.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) else: self.add_subsystem('indep_vars', indep_var_comp, promotes=[]) if self.options['DVGeo']: from openaerostruct.geometry.ffd_component import GeometryMesh indep_var_comp.add_output('shape', val=np.zeros( (surface['mx'], surface['my'])), units='m') if 't_over_c_cp' in surface.keys(): n_cp = len(surface['t_over_c_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 't_over_c_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['t_over_c_cp'], promotes_outputs=['t_over_c']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c') if surface.get('t_over_c_cp_dv', True): indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) self.add_subsystem('mesh', GeometryMesh(surface=surface, DVGeo=self.options['DVGeo']), promotes_inputs=['shape'], promotes_outputs=['mesh']) else: from openaerostruct.geometry.geometry_mesh import GeometryMesh bsp_inputs = [] if 'twist_cp' in surface.keys(): n_cp = len(surface['twist_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny)) comp = self.add_subsystem( 'twist_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['twist_cp'], promotes_outputs=['twist']) comp.add_spline(y_cp_name='twist_cp', y_interp_name='twist') bsp_inputs.append('twist') # Since default assumption is that we want tail rotation as a design variable, add this to allow for trimmed drag polar where the tail rotation should not be a design variable if surface.get('twist_cp_dv', True): indep_var_comp.add_output('twist_cp', val=surface['twist_cp'], units='deg') if 'chord_cp' in surface.keys(): n_cp = len(surface['chord_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny)) comp = self.add_subsystem( 'chord_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['chord_cp'], promotes_outputs=['chord']) comp.add_spline(y_cp_name='chord_cp', y_interp_name='chord') bsp_inputs.append('chord') if surface.get('chord_cp_dv', True): indep_var_comp.add_output('chord_cp', val=surface['chord_cp'], units='m') if 't_over_c_cp' in surface.keys(): n_cp = len(surface['t_over_c_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 't_over_c_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['t_over_c_cp'], promotes_outputs=['t_over_c']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c') if surface.get('t_over_c_cp_dv', True): indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) if 'xshear_cp' in surface.keys(): n_cp = len(surface['xshear_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny)) comp = self.add_subsystem( 'xshear_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['xshear_cp'], promotes_outputs=['xshear']) comp.add_spline(y_cp_name='xshear_cp', y_interp_name='xshear') bsp_inputs.append('xshear') if surface.get('xshear_cp_dv', True): indep_var_comp.add_output('xshear_cp', val=surface['xshear_cp'], units='m') if 'yshear_cp' in surface.keys(): n_cp = len(surface['yshear_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny)) comp = self.add_subsystem( 'yshear_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['yshear_cp'], promotes_outputs=['yshear']) comp.add_spline(y_cp_name='yshear_cp', y_interp_name='yshear') bsp_inputs.append('yshear') if surface.get('yshear_cp_dv', True): indep_var_comp.add_output('yshear_cp', val=surface['yshear_cp'], units='m') if 'zshear_cp' in surface.keys(): n_cp = len(surface['zshear_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny)) comp = self.add_subsystem( 'zshear_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['zshear_cp'], promotes_outputs=['zshear']) comp.add_spline(y_cp_name='zshear_cp', y_interp_name='zshear') bsp_inputs.append('zshear') if surface.get('zshear_cp_dv', True): indep_var_comp.add_output('zshear_cp', val=surface['zshear_cp'], units='m') if 'sweep' in surface.keys(): bsp_inputs.append('sweep') if surface.get('sweep_dv', True): indep_var_comp.add_output('sweep', val=surface['sweep'], units='deg') if 'span' in surface.keys(): bsp_inputs.append('span') if surface.get('span_dv', True): indep_var_comp.add_output('span', val=surface['span'], units='m') if 'dihedral' in surface.keys(): bsp_inputs.append('dihedral') if surface.get('dihedral_dv', True): indep_var_comp.add_output('dihedral', val=surface['dihedral'], units='deg') if 'taper' in surface.keys(): bsp_inputs.append('taper') if surface.get('taper_dv', True): indep_var_comp.add_output('taper', val=surface['taper']) self.add_subsystem('mesh', GeometryMesh(surface=surface), promotes_inputs=bsp_inputs, promotes_outputs=['mesh'])
def setup(self): E = self.options['E'] L = self.options['L'] b = self.options['b'] volume = self.options['volume'] max_bending = self.options['max_bending'] num_elements = self.options['num_elements'] num_nodes = num_elements + 1 num_cp = self.options['num_cp'] num_load_cases = self.options['num_load_cases'] parallel_derivs = self.options['parallel_derivs'] x_interp = sine_distribution(num_elements) comp = om.SplineComp(method='bsplines', num_cp=num_cp, x_interp_val=x_interp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h') self.add_subsystem('interp', comp) I_comp = MomentOfInertiaComp(num_elements=num_elements, b=b) self.add_subsystem('I_comp', I_comp) comp = LocalStiffnessMatrixComp(num_elements=num_elements, E=E, L=L) self.add_subsystem('local_stiffness_matrix_comp', comp) # Parallel Subsystem for load cases. par = self.add_subsystem('parallel', om.ParallelGroup()) # Determine how to split cases up over the available procs. nprocs = self.comm.size divide = divide_cases(num_load_cases, nprocs) for j, this_proc in enumerate(divide): num_rhs = len(this_proc) name = 'sub_%d' % j sub = par.add_subsystem(name, om.Group()) # Load is a sinusoidal distributed force of varying spatial frequency. force_vector = np.zeros((2 * num_nodes, num_rhs)) for i, k in enumerate(this_proc): end = 1.5 * np.pi if num_load_cases > 1: end += k * 0.5 * np.pi / (num_load_cases - 1) x = np.linspace(0, end, num_nodes) f = - np.sin(x) force_vector[0:-1:2, i] = f comp = MultiStatesComp(num_elements=num_elements, force_vector=force_vector, num_rhs=num_rhs) sub.add_subsystem('states_comp', comp) comp = MultiStressComp(num_elements=num_elements, E=E, num_rhs=num_rhs) sub.add_subsystem('stress_comp', comp) self.connect('local_stiffness_matrix_comp.K_local', 'parallel.%s.states_comp.K_local' % name) for k in range(num_rhs): sub.connect('states_comp.d_%d' % k, 'stress_comp.displacements_%d' % k, src_indices=np.arange(2 *num_nodes)) if parallel_derivs: color = 'red_%d' % k else: color = None comp = om.KSComp(width=num_elements, upper=max_bending, add_constraint=self.options['ks_add_constraint'], parallel_deriv_color=color) sub.add_subsystem('KS_%d' % k, comp) sub.connect('stress_comp.stress_%d' % k, 'KS_%d.g' % k) if not self.options['ks_add_constraint']: sub.add_constraint('KS_%d.KS' % k, upper=0.0, parallel_deriv_color=color) comp = VolumeComp(num_elements=num_elements, b=b, L=L) self.add_subsystem('volume_comp', comp) self.connect('interp.h', 'I_comp.h') self.connect('interp.h', 'volume_comp.h') self.connect('I_comp.I', 'local_stiffness_matrix_comp.I') self.add_design_var('interp.h_cp', lower=1e-2, upper=10.) self.add_objective('volume_comp.volume')
def setup(self): E = self.options['E'] L = self.options['L'] b = self.options['b'] volume = self.options['volume'] num_elements = self.options['num_elements'] num_nodes = num_elements + 1 num_cp = self.options['num_cp'] num_load_cases = self.options['num_load_cases'] inputs_comp = om.IndepVarComp() inputs_comp.add_output('h_cp', shape=num_cp) self.add_subsystem('inputs_comp', inputs_comp) x_interp = sine_distribution(num_elements) comp = om.SplineComp(method='bsplines', num_cp=num_cp, x_interp_val=x_interp) comp.add_spline(y_cp_name='h_cp', y_interp_name='h') self.add_subsystem('interp', comp) I_comp = MomentOfInertiaComp(num_elements=num_elements, b=b) self.add_subsystem('I_comp', I_comp) comp = LocalStiffnessMatrixComp(num_elements=num_elements, E=E, L=L) self.add_subsystem('local_stiffness_matrix_comp', comp) # Parallel Subsystem for load cases. par = self.add_subsystem('parallel', om.ParallelGroup()) # Determine how to split cases up over the available procs. nprocs = self.comm.size divide = divide_cases(num_load_cases, nprocs) obj_srcs = [] for j, this_proc in enumerate(divide): num_rhs = len(this_proc) name = 'sub_%d' % j sub = par.add_subsystem(name, om.Group()) # Load is a sinusoidal distributed force of varying spatial frequency. force_vector = np.zeros((2 * num_nodes, num_rhs)) for i, k in enumerate(this_proc): end = 1.5 * np.pi if num_load_cases > 1: end += k * 0.5 * np.pi / (num_load_cases - 1) x = np.linspace(0, end, num_nodes) f = -np.sin(x) force_vector[0:-1:2, i] = f comp = MultiStatesComp(num_elements=num_elements, force_vector=force_vector, num_rhs=num_rhs) sub.add_subsystem('states_comp', comp) comp = MultiComplianceComp(num_elements=num_elements, force_vector=force_vector, num_rhs=num_rhs) sub.add_subsystem('compliance_comp', comp) self.connect('local_stiffness_matrix_comp.K_local', 'parallel.%s.states_comp.K_local' % name) for k in range(num_rhs): sub.connect('states_comp.d_%d' % k, 'compliance_comp.displacements_%d' % k, src_indices=np.arange(2 * num_nodes)) obj_srcs.append('parallel.%s.compliance_comp.compliance_%d' % (name, k)) comp = VolumeComp(num_elements=num_elements, b=b, L=L) self.add_subsystem('volume_comp', comp) comp = om.ExecComp([ 'obj = ' + ' + '.join(['compliance_%d' % i for i in range(num_load_cases)]) ]) self.add_subsystem('obj_sum', comp) for j, src in enumerate(obj_srcs): self.connect(src, 'obj_sum.compliance_%d' % j) self.connect('inputs_comp.h_cp', 'interp.h_cp') self.connect('interp.h', 'I_comp.h') self.connect('I_comp.I', 'local_stiffness_matrix_comp.I') self.connect('interp.h', 'volume_comp.h') self.add_design_var('inputs_comp.h_cp', lower=1e-2, upper=10.) self.add_constraint('volume_comp.volume', equals=volume) self.add_objective('obj_sum.obj')
def test2(self): """ This is for checking the computation. """ surface = get_default_surfaces()[0] surface['t_over_c_cp'] = np.array([0.1, 0.15, 0.2]) surface['spar_thickness_cp'] = np.array([0.004, 0.008, 0.02]) surface['skin_thickness_cp'] = np.array([0.01, 0.015, 0.021]) surface['fem_chords_cp'] = np.array([2., 3., 4.]) surface['streamwise_chords_cp'] = np.array([3., 4., 5.]) surface['fem_twists_cp'] = np.array([5., 3., 2.]) / 180. * np.pi surface['data_x_upper'] = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') surface['data_x_lower'] = np.array([ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ], dtype='complex128') surface['data_y_upper'] = np.array([ 0.0447, 0.046, 0.0472, 0.0484, 0.0495, 0.0505, 0.0514, 0.0523, 0.0531, 0.0538, 0.0545, 0.0551, 0.0557, 0.0563, 0.0568, 0.0573, 0.0577, 0.0581, 0.0585, 0.0588, 0.0591, 0.0593, 0.0595, 0.0597, 0.0599, 0.06, 0.0601, 0.0602, 0.0602, 0.0602, 0.0602, 0.0602, 0.0601, 0.06, 0.0599, 0.0598, 0.0596, 0.0594, 0.0592, 0.0589, 0.0586, 0.0583, 0.058, 0.0576, 0.0572, 0.0568, 0.0563, 0.0558, 0.0553, 0.0547, 0.0541 ], dtype='complex128') surface['data_y_lower'] = np.array([ -0.0447, -0.046, -0.0473, -0.0485, -0.0496, -0.0506, -0.0515, -0.0524, -0.0532, -0.054, -0.0547, -0.0554, -0.056, -0.0565, -0.057, -0.0575, -0.0579, -0.0583, -0.0586, -0.0589, -0.0592, -0.0594, -0.0595, -0.0596, -0.0597, -0.0598, -0.0598, -0.0598, -0.0598, -0.0597, -0.0596, -0.0594, -0.0592, -0.0589, -0.0586, -0.0582, -0.0578, -0.0573, -0.0567, -0.0561, -0.0554, -0.0546, -0.0538, -0.0529, -0.0519, -0.0509, -0.0497, -0.0485, -0.0472, -0.0458, -0.0444 ], dtype='complex128') surface['original_wingbox_airfoil_t_over_c'] = 0.1 mesh = surface['mesh'] ny = mesh.shape[1] nx = mesh.shape[0] n_cp = len(surface['t_over_c_cp']) prob = om.Problem() indep_var_comp = om.IndepVarComp() indep_var_comp.add_output('t_over_c_cp', val=surface['t_over_c_cp']) indep_var_comp.add_output('spar_thickness_cp', val=surface['spar_thickness_cp']) indep_var_comp.add_output('skin_thickness_cp', val=surface['skin_thickness_cp']) indep_var_comp.add_output('fem_chords_cp', val=surface['fem_chords_cp']) indep_var_comp.add_output('streamwise_chords_cp', val=surface['streamwise_chords_cp']) indep_var_comp.add_output('fem_twists_cp', val=surface['fem_twists_cp']) prob.model.add_subsystem('indep_var_comp', indep_var_comp, promotes=['*']) x_interp = np.linspace(0., 1., int(ny - 1)) comp = prob.model.add_subsystem( 'bsplines_comp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['*'], promotes_outputs=['*']) comp.add_spline(y_cp_name='t_over_c_cp', y_interp_name='t_over_c') comp.add_spline(y_cp_name='skin_thickness_cp', y_interp_name='skin_thickness', y_units='m') comp.add_spline(y_cp_name='spar_thickness_cp', y_interp_name='spar_thickness', y_units='m') comp.add_spline(y_cp_name='fem_chords_cp', y_interp_name='fem_chords', y_units='m') comp.add_spline(y_cp_name='streamwise_chords_cp', y_interp_name='streamwise_chords', y_units='m') comp.add_spline(y_cp_name='fem_twists_cp', y_interp_name='fem_twists', y_units='deg') comp = SectionPropertiesWingbox(surface=surface) prob.model.add_subsystem('sec_prop_wb', comp, promotes=['*']) prob.setup() # om.view_model(prob) prob.run_model() # print( prob['A'] ) # print( prob['A_enc'] ) # print( prob['A_int'] ) # print( prob['Iy'] ) # print( prob['Qz'] ) # print( prob['Iz'] ) # print( prob['J'] ) # print( prob['htop'] ) # print( prob['hbottom'] ) # print( prob['hfront'] ) # print( prob['hrear'] ) assert_rel_error(self, prob['A'], np.array([0.02203548, 0.0563726, 0.11989703]), 1e-6) assert_rel_error(self, prob['A_enc'], np.array([0.3243776, 0.978003, 2.17591]), 1e-6) assert_rel_error(self, prob['A_int'], np.array([0.3132502, 0.949491, 2.11512]), 1e-6) assert_rel_error(self, prob['Iy'], np.array([0.00218612, 0.01455083, 0.06342765]), 1e-6) assert_rel_error(self, prob['Qz'], np.array([0.00169233, 0.00820558, 0.02707493]), 1e-6) assert_rel_error(self, prob['Iz'], np.array([0.00055292, 0.00520911, 0.02785168]), 1e-6) assert_rel_error(self, prob['J'], np.array([0.00124939, 0.01241967, 0.06649673]), 1e-6) assert_rel_error(self, prob['htop'], np.array([0.19106873, 0.36005945, 0.5907887]), 1e-6) assert_rel_error(self, prob['hbottom'], np.array([0.19906584, 0.37668887, 0.61850335]), 1e-6) assert_rel_error(self, prob['hfront'], np.array([0.52341176, 0.78649186, 1.04902676]), 1e-6) assert_rel_error(self, prob['hrear'], np.array([0.47524073, 0.71429312, 0.95303545]), 1e-6)
def setup(self): surface = self.options['surface'] connect_geom_DVs = self.options['connect_geom_DVs'] mesh = surface['mesh'] ny = mesh.shape[1] if connect_geom_DVs: # Add independent variables that do not belong to a specific component indep_var_comp = om.IndepVarComp() # Add structural components to the surface-specific group self.add_subsystem('indep_vars', indep_var_comp, promotes=['*']) if 'thickness_cp' in surface.keys(): n_cp = len(surface['thickness_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 'thickness_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['thickness_cp'], promotes_outputs=['thickness']) comp.add_spline(y_cp_name='thickness_cp', y_interp_name='thickness', y_units='m') if connect_geom_DVs: indep_var_comp.add_output('thickness_cp', val=surface['thickness_cp'], units='m') if 'radius_cp' in surface.keys(): n_cp = len(surface['radius_cp']) # Add bspline components for active bspline geometric variables. x_interp = np.linspace(0., 1., int(ny - 1)) comp = self.add_subsystem( 'radius_bsp', om.SplineComp(method='bsplines', x_interp_val=x_interp, num_cp=n_cp, interp_options={'order': min(n_cp, 4)}), promotes_inputs=['radius_cp'], promotes_outputs=['radius']) comp.add_spline(y_cp_name='radius_cp', y_interp_name='radius', y_units='m') if connect_geom_DVs: indep_var_comp.add_output('radius_cp', val=surface['radius_cp'], units='m') else: self.add_subsystem('radius_comp', RadiusComp(surface=surface), promotes_inputs=['mesh', 't_over_c'], promotes_outputs=['radius']) self.add_subsystem('tube', SectionPropertiesTube(surface=surface), promotes_inputs=['thickness', 'radius'], promotes_outputs=['A', 'Iy', 'Iz', 'J'])