def test_swept_wing_with_controls(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input( input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 aircraft_dict["wings"]["h_stab"]["sweep"] = 30.0 control_state = {"elevator": 5.0, "aileron": 5.0, "rudder": 5.0} # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"] - 32.13425691779829) < 1e-10 assert abs(FM["test_plane"]["total"]["FD"] - 4.280678609518078) < 1e-10 assert abs(FM["test_plane"]["total"]["FS"] + 4.397707239991741) < 1e-10 assert abs(FM["test_plane"]["total"]["Fx"] + 3.1566015424292044) < 1e-10 assert abs(FM["test_plane"]["total"]["Fy"] + 4.397707239991741) < 1e-10 assert abs(FM["test_plane"]["total"]["Fz"] + 32.26407512573988) < 1e-10 assert abs(FM["test_plane"]["total"]["Mx"] + 17.910786767633244) < 1e-10 assert abs(FM["test_plane"]["total"]["My"] + 76.03674820597931) < 1e-10 assert abs(FM["test_plane"]["total"]["Mz"] - 13.868978522091632) < 1e-10
def test_stability_derivatives(): # Tests the calculation of the stability derivatives # Load scene scene = MX.Scene(input_file) stab_derivs = scene.stability_derivatives() assert abs(stab_derivs["test_plane"]["CL,a"] - 6.322012906729068) < 1e-10 assert abs(stab_derivs["test_plane"]["CD,a"] - 0.3246111615552763) < 1e-10 assert abs(stab_derivs["test_plane"]["CS,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cx,a"] - 0.11707169911153548) < 1e-10 assert abs(stab_derivs["test_plane"]["Cy,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cz,a"] + 6.336555845802937) < 1e-10 assert abs(stab_derivs["test_plane"]["Cl,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cm,a"] + 3.946036942099846) < 1e-10 assert abs(stab_derivs["test_plane"]["Cn,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CL,b"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CD,b"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CS,b"] + 0.8157254960313394) < 1e-9 assert abs(stab_derivs["test_plane"]["Cx,b"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cy,b"] + 0.8304002728742348) < 1e-9 assert abs(stab_derivs["test_plane"]["Cz,b"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cl,b"] + 0.1615386223535695) < 1e-10 assert abs(stab_derivs["test_plane"]["Cm,b"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cn,b"] - 0.6171846005680138) < 1e-9
def test_damping_derivatives(): # Test the calculation of the damping derivatives # Load scene scene = MX.Scene(input_file) damp_derivs = scene.aircraft_damping_derivatives() # There's something about how NLL calculates these cases that introduces a little more numerical error... assert abs(damp_derivs["test_plane"]["CL,pbar"] - 0.00037018702894742184) < 1e-6 assert abs(damp_derivs["test_plane"]["CD,pbar"] + 6.60883695078468e-05) < 1e-6 assert abs(damp_derivs["test_plane"]["CS,pbar"] + 0.09305320429644524) < 1e-6 assert abs(damp_derivs["test_plane"]["Cx,pbar"] - 7.896745125857141e-05) < 1e-6 assert abs(damp_derivs["test_plane"]["Cy,pbar"] + 0.09305320429644524) < 1e-6 assert abs(damp_derivs["test_plane"]["Cz,pbar"] + 0.0003676550701381398) < 1e-6 assert abs(damp_derivs["test_plane"]["Cl,pbar"] + 2.55335879459208) < 1e-6 assert abs(damp_derivs["test_plane"]["Cm,pbar"] + 0.0011593362887751812) < 1e-6 assert abs(damp_derivs["test_plane"]["Cn,pbar"] - 0.02514714847131455) < 1e-6 assert abs(damp_derivs["test_plane"]["CL,qbar"] - 13.019918503532345) < 1e-6 assert abs(damp_derivs["test_plane"]["CD,qbar"] - 0.3090180115277938) < 1e-6 assert abs(damp_derivs["test_plane"]["CS,qbar"] + 0.013965339163743515) < 1e-6 assert abs(damp_derivs["test_plane"]["Cx,qbar"] - 0.14555883677632234) < 1e-6 assert abs(damp_derivs["test_plane"]["Cy,qbar"] + 0.013965339163743515) < 1e-6 assert abs(damp_derivs["test_plane"]["Cz,qbar"] + 13.022771694040092) < 1e-6 assert abs(damp_derivs["test_plane"]["Cl,qbar"] + 0.0011967792488973804) < 1e-6 assert abs(damp_derivs["test_plane"]["Cm,qbar"] + 36.6535222940767) < 1e-6 assert abs(damp_derivs["test_plane"]["Cn,qbar"] - 0.010480645283789216) < 1e-6 assert abs(damp_derivs["test_plane"]["CL,rbar"] + 2.211564265053312e-09) < 1e-6 assert abs(damp_derivs["test_plane"]["CD,rbar"] + 4.9465639917478654e-11) < 1e-6 assert abs(damp_derivs["test_plane"]["CS,rbar"] - 1.2322179506649182) < 1e-6 assert abs(damp_derivs["test_plane"]["Cx,rbar"] + 2.776858604169874e-11) < 1e-6 assert abs(damp_derivs["test_plane"]["Cy,rbar"] - 1.2322179506649182) < 1e-6 assert abs(damp_derivs["test_plane"]["Cz,rbar"] - 2.2119805986875463e-09) < 1e-6 assert abs(damp_derivs["test_plane"]["Cl,rbar"] - 0.36543638451918914) < 1e-6 assert abs(damp_derivs["test_plane"]["Cm,rbar"] - 6.248890294102694e-09) < 1e-6 assert abs(damp_derivs["test_plane"]["Cn,rbar"] + 0.9323904254656564) < 1e-6
def test_stability_derivatives(): # Tests the calculation of the stability derivatives # Load scene scene = MX.Scene(input_file) stab_derivs = scene.aircraft_stability_derivatives() assert abs(stab_derivs["test_plane"]["CL,a"] - 6.325561939795834) < 1e-10 assert abs(stab_derivs["test_plane"]["CD,a"] - 0.32484784717545706) < 1e-10 assert abs(stab_derivs["test_plane"]["CS,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cx,a"] - 0.11701146202557859) < 1e-10 assert abs(stab_derivs["test_plane"]["Cy,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cz,a"] + 6.340112485605566) < 1e-10 assert abs(stab_derivs["test_plane"]["Cl,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cm,a"] + 3.951172935738557) < 1e-10 assert abs(stab_derivs["test_plane"]["Cn,a"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CL,B"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CD,B"]) < 1e-10 assert abs(stab_derivs["test_plane"]["CS,B"] + 0.8173565005198824) < 1e-10 assert abs(stab_derivs["test_plane"]["Cx,B"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cy,B"] + 0.8320251585209351) < 1e-10 assert abs(stab_derivs["test_plane"]["Cz,B"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cl,B"] + 0.13833770562075048) < 1e-10 assert abs(stab_derivs["test_plane"]["Cm,B"]) < 1e-10 assert abs(stab_derivs["test_plane"]["Cn,B"] - 0.6187734326780242) < 1e-10
def test_twist_as_f_of_span(): # Tests that twist is properly returned as a function of span # Load input input_dict, airplane_name, airplane_dict, state, control_state = MX.helpers.parse_input( input_file) # Alter input for key in airplane_dict["wings"]: airplane_dict["wings"][key].pop("sweep", None) if "vertical" not in key: airplane_dict["wings"][key].pop("dihedral", None) airplane_dict["wings"][key]["twist"] = [[0.0, 0.0], [0.5, 5.0], [1.0, -5.0]] # Load scene scene = MX.Scene(input_dict) scene.add_aircraft(airplane_name, airplane_dict, state=state, control_state=control_state) spans = [0.0, 0.1, 0.2] twists = [0.0, 0.017453292519943295, 0.03490658503988659] wing_dict = scene._airplanes[airplane_name].wing_segments for key in wing_dict: for span, correct_twist in zip(spans, twists): twist = wing_dict[key].get_twist(span) print(twist) assert np.allclose(twist, correct_twist, rtol=0.0, atol=1e-10)
def bire_case(params, inp_dir): [alpha, beta, d_e, d_a, d_r, p, q, r] = params rotation_angle = str(int(d_r)) try: f = open(inp_dir + 'BIRE_input_dr_' + rotation_angle + '.json', ) except FileNotFoundError: create_inputs(inp_dir, d_r) input_file = inp_dir + 'BIRE_input_dr_' + rotation_angle + '.json' BIRE_scene = mx.Scene(input_file) forces_options = { 'body_frame': True, 'stab_frame': False, 'wind_frame': True, 'dimensional': False, 'verbose': False } rates = [p, q, r] BIRE_scene.set_aircraft_state(state={ "alpha": alpha, "beta": beta, "angular_rates": rates, "velocity": 222.5211 }) BIRE_scene.set_aircraft_control_state(control_state={ "elevator": d_e, "aileron": d_a }) x = BIRE_scene.solve_forces(**forces_options)["BIRE"]["total"] fm = [x['CD'], x['CS'], x['CL'], x['Cl'], x['Cm'], x['Cn']] return fm
def test_pitch_trim_orientation(): # Alter input with open(input_file, 'r') as input_file_handle: input_dict = json.load(input_file_handle) input_dict["scene"]["aircraft"]["test_plane"]["control_state"] = { "elevator" : 0.0, "rudder" : 0.0, "aileron" : 0.0 } input_dict["scene"]["aircraft"]["test_plane"]["state"] = { "position" : [0, 0, 1000], "angular_rates" : [0.0, 0.0, 0.0], "velocity" : 100, "alpha" : 2.0, "beta" : 0.0 } # Create scene scene = MX.Scene(input_dict) trim = scene.pitch_trim_using_orientation(CL=0.1, Cm=0.2) print(trim) assert abs(trim[0]["orientation"][0]-0.9999997533435244)<1e-10 assert abs(trim[0]["orientation"][1])<1e-10 assert abs(trim[0]["orientation"][2]+0.0007023623640411208)<1e-10 assert abs(trim[0]["orientation"][3])<1e-10 assert abs(trim[1]["elevator"]+3.8073227363076954)<1e-10
def test_tapered_wing(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input(input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["chord"] = [[0.0, 1.0],[1.0, 0.5]] aircraft_dict["wings"]["main_wing"]["dihedral"] = 10.0 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"]-17.722533099036767)<1e-10 assert abs(FM["test_plane"]["total"]["FD"]-1.184375545596456)<1e-10 assert abs(FM["test_plane"]["total"]["FS"])<1e-10 assert abs(FM["test_plane"]["total"]["Fx"]+0.565146570565037)<1e-10 assert abs(FM["test_plane"]["total"]["Fy"])<1e-10 assert abs(FM["test_plane"]["total"]["Fz"]+17.753071121167718)<1e-10 assert abs(FM["test_plane"]["total"]["Mx"])<1e-10 assert abs(FM["test_plane"]["total"]["My"]+13.573362229826092)<1e-10 assert abs(FM["test_plane"]["total"]["Mz"])<1e-10
def test_step_change_in_twist_wing(): # Tests the NLL algorithm correctly calculates a wing with a step change in twist # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input(input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["chord"] = [[0.0, 1.0],[1.0, 0.5]] aircraft_dict["wings"]["main_wing"]["dihedral"] = 10.0 aircraft_dict["wings"]["main_wing"]["twist"] = [[0.0, 5.0], [0.5, 5.0], [0.5, 0.0], [1.0, 0.0]] aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 aircraft_dict["wings"]["main_wing"]["grid"]["N"] = 100 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"]-28.35481401045731)<1e-10 assert abs(FM["test_plane"]["total"]["FD"]-3.606067666817706)<1e-10 assert abs(FM["test_plane"]["total"]["FS"])<1e-10 assert abs(FM["test_plane"]["total"]["Fx"]+2.614302209769785)<1e-10 assert abs(FM["test_plane"]["total"]["Fy"])<1e-10 assert abs(FM["test_plane"]["total"]["Fz"]+28.463390970530668)<1e-10 assert abs(FM["test_plane"]["total"]["Mx"])<1e-10 assert abs(FM["test_plane"]["total"]["My"]+18.601536350947654)<1e-10 assert abs(FM["test_plane"]["total"]["Mz"])<1e-10
def test_swept_wing(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input(input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"]-19.783243781894804)<1e-10 assert abs(FM["test_plane"]["total"]["FD"]-1.5107597754297257)<1e-10 assert abs(FM["test_plane"]["total"]["FS"])<1e-10 assert abs(FM["test_plane"]["total"]["Fx"]+0.8194142102628863)<1e-10 assert abs(FM["test_plane"]["total"]["Fy"])<1e-10 assert abs(FM["test_plane"]["total"]["Fz"]+19.823917120109112)<1e-10 assert abs(FM["test_plane"]["total"]["Mx"])<1e-10 assert abs(FM["test_plane"]["total"]["My"]+30.137871282759612)<1e-10 assert abs(FM["test_plane"]["total"]["Mz"])<1e-10
def test_swept_wing_with_controls(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input(input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 aircraft_dict["wings"]["h_stab"]["sweep"] = 30.0 control_state = { "elevator" : 5.0, "aileron" : 5.0, "rudder" : 5.0 } # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"]-32.44429480507447)<1e-10 assert abs(FM["test_plane"]["total"]["FD"]-4.283836550324898)<1e-10 assert abs(FM["test_plane"]["total"]["FS"]+4.414822066505888)<1e-10 assert abs(FM["test_plane"]["total"]["Fx"]+3.1489373932791636)<1e-10 assert abs(FM["test_plane"]["total"]["Fy"]+4.414822066505888)<1e-10 assert abs(FM["test_plane"]["total"]["Fz"]+32.57403435685684)<1e-10 assert abs(FM["test_plane"]["total"]["Mx"]+17.905545144497058)<1e-10 assert abs(FM["test_plane"]["total"]["My"]+76.51699263955834)<1e-10 assert abs(FM["test_plane"]["total"]["Mz"]-13.915921134824531)<1e-10
def test_pitch_trim_with_finite_moment(): # Alter input with open(input_file, 'r') as input_file_handle: input_dict = json.load(input_file_handle) input_dict["scene"]["aircraft"]["test_plane"]["control_state"] = { "elevator" : 0.0, "rudder" : 0.0, "aileron" : 0.0 } input_dict["scene"]["aircraft"]["test_plane"]["state"] = { "position" : [0, 0, 1000], "angular_rates" : [0.0, 0.0, 0.0], "velocity" : 100, "alpha" : 2.0, "beta" : 0.0 } # Create scene scene = MX.Scene(input_dict) trim = scene.pitch_trim(CL=0.1, Cm=0.2) print(trim) assert abs(trim["test_plane"]["alpha"]-1.9195151950855374)<1e-10 assert abs(trim["test_plane"]["elevator"]+3.807322736307231)<1e-10
def trim_func(x,Cl,static_margin, Cn_beta, Cl_beta): with open('glider_2.0.json') as f: airplane = json.load(f) f.close() with open('scene.json') as f: scene = json.load(f) f.close() wing_twist = 2.5 # angle to twist wing down from mounting angle. airplane['CG'][0] = x[0] airplane['wings']['main_wing']['twist'] = [[0.0, x[1], 1.0, x[1]-wing_twist]] airplane['wings']['outside_wings']['twist'] = [[0.0, 0, 1.0, 0]] airplane['wings']['H_Stab']['connect_to']['dx'] = x[2] airplane['wings']['V_Stab']['connect_to']['dx'] = x[3] airplane['wings']['main_wing']['dihedral'] = x[4] with open('glider_2.0.json', 'w') as fp: json.dump(airplane,fp,indent = 4) fp.close() my_scene = MX.Scene('scene.json') FM_results = my_scene.solve_forces(non_dimensional = True) derivs = my_scene.derivatives()['glider_2.0'] residual = FM_results['glider_2.0']['total']['Cm']**2 + (derivs['stability']['%_static_margin']/100-static_margin)**2+\ + (derivs['stability']['Cn,b'] - Cn_beta)**2 + (derivs['stability']['Cl,b']-Cl_beta)**2 + (FM_results['glider_2.0']['total']['CL']-Cl)**2 print('The moment coefficient is: ',FM_results['glider_2.0']['total']['Cm']) print('The static margin is: ',derivs['stability']['%_static_margin']/100) print('Cn,b is: ',derivs['stability']['Cn,b']) print('Cl,b is: ',derivs['stability']['Cl,b']) print('Cl is: ',FM_results['glider_2.0']['total']['CL']) print('L/D is: ',FM_results['glider_2.0']['total']['CL']/FM_results['glider_2.0']['total']['CD']) return residual
def test_target_CL(): # Alter input with open(input_file, 'r') as input_file_handle: input_dict = json.load(input_file_handle) input_dict["scene"]["aircraft"]["test_plane"]["control_state"] = { "elevator" : 0.0, "rudder" : 0.0, "aileron" : 0.0 } input_dict["scene"]["aircraft"]["test_plane"]["state"] = { "position" : [0, 0, 1000], "angular_rates" : [0.0, 0.0, 0.0], "velocity" : 100, "alpha" : 2.0, "beta" : 0.0 } # Create scene scene = MX.Scene(input_dict) alpha = scene.target_CL(CL=0.5) print(alpha) assert abs(alpha-4.531085683208453)<1e-10
def test_pitch_trim(): # Alter input with open(input_file, 'r') as input_file_handle: input_dict = json.load(input_file_handle) input_dict["scene"]["aircraft"]["test_plane"]["control_state"] = { "elevator" : 0.0, "rudder" : 0.0, "aileron" : 0.0 } input_dict["scene"]["aircraft"]["test_plane"]["state"] = { "position" : [0, 0, 1000], "angular_rates" : [0.0, 0.0, 0.0], "velocity" : 100, "alpha" : 2.0, "beta" : 0.0 } # Create scene scene = MX.Scene(input_dict) trim = scene.pitch_trim() print(trim) assert abs(trim["test_plane"]["alpha"]-12.27375383887546)<1e-10 assert abs(trim["test_plane"]["elevator"]+10.303072276682208)<1e-10
def test_swept_wing(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input( input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"] - 19.68954318567083) < 1e-10 assert abs(FM["test_plane"]["total"]["FD"] - 1.5070187293045343) < 1e-10 assert abs(FM["test_plane"]["total"]["FS"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fx"] + 0.8189455467308557) < 1e-10 assert abs(FM["test_plane"]["total"]["Fy"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fz"] + 19.73014304312974) < 1e-10 assert abs(FM["test_plane"]["total"]["Mx"]) < 1e-10 assert abs(FM["test_plane"]["total"]["My"] + 30.285634979503445) < 1e-10 assert abs(FM["test_plane"]["total"]["Mz"]) < 1e-10
def test_tapered_wing(): # Tests the NLL algorithm correctly calculates a swept wing # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input( input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["chord"] = [[0.0, 1.0], [1.0, 0.5]] aircraft_dict["wings"]["main_wing"]["dihedral"] = 10.0 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"] - 17.728023315126524) < 1e-10 assert abs(FM["test_plane"]["total"]["FD"] - 1.1847391542471732) < 1e-10 assert abs(FM["test_plane"]["total"]["FS"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fx"] + 0.5653183519368681) < 1e-10 assert abs(FM["test_plane"]["total"]["Fy"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fz"] + 17.758570682525082) < 1e-10 assert abs(FM["test_plane"]["total"]["Mx"]) < 1e-10 assert abs(FM["test_plane"]["total"]["My"] + 13.56985584130499) < 1e-10 assert abs(FM["test_plane"]["total"]["Mz"]) < 1e-10
def test_step_change_in_twist_wing(): # Tests the NLL algorithm correctly calculates a wing with a step change in twist # Load input input_dict, aircraft_name, aircraft_dict, state, control_state = MX.helpers.parse_input( input_file) # Alter input input_dict["solver"]["type"] = "nonlinear" aircraft_dict["wings"]["main_wing"]["chord"] = [[0.0, 1.0], [1.0, 0.5]] aircraft_dict["wings"]["main_wing"]["dihedral"] = 10.0 aircraft_dict["wings"]["main_wing"]["twist"] = [[0.0, 5.0], [0.5, 5.0], [0.5, 0.0], [1.0, 0.0]] aircraft_dict["wings"]["main_wing"]["sweep"] = 30.0 aircraft_dict["wings"]["main_wing"]["grid"]["N"] = 100 # Create scene scene = MX.Scene(input_dict) scene.add_aircraft(aircraft_name, aircraft_dict, state=state, control_state=control_state) FM = scene.solve_forces(non_dimensional=True) print(json.dumps(FM["test_plane"]["total"], indent=4)) assert abs(FM["test_plane"]["total"]["FL"] - 28.12285963876808) < 1e-10 assert abs(FM["test_plane"]["total"]["FD"] - 3.5693179079748987) < 1e-10 assert abs(FM["test_plane"]["total"]["FS"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fx"] + 2.585669928717018) < 1e-10 assert abs(FM["test_plane"]["total"]["Fy"]) < 1e-10 assert abs(FM["test_plane"]["total"]["Fz"] + 28.23029535108992) < 1e-10 assert abs(FM["test_plane"]["total"]["Mx"]) < 1e-10 assert abs(FM["test_plane"]["total"]["My"] + 18.969204048301485) < 1e-10 assert abs(FM["test_plane"]["total"]["Mz"]) < 1e-10
def test_distributions(): #Load scene scene = MX.Scene(input_file) dist = scene.distributions() assert np.allclose(dist["test_plane"]["main_wing_right"]["chord"], 1.0, rtol=0.0, atol=1e-10) assert np.allclose(dist["test_plane"]["main_wing_right"]["sweep"], 0.0, rtol=0.0, atol=1e-10) assert np.allclose(dist["test_plane"]["main_wing_left"]["dihedral"], 0.0, rtol=0.0, atol=1e-10) assert np.allclose(dist["test_plane"]["v_stab_right"]["dihedral"], 1.5707963267948966, rtol=0.0, atol=1e-10) assert np.allclose(dist["test_plane"]["h_stab_left"]["twist"], 0.0, rtol=0.0, atol=1e-10)
def test_compute_constant_swept_dihedral_wing_tip_location(): # Tests the tip of the wing is in the proper location for a wing with # both constant sweep and constant dihedral # Alter input with open(input_file, 'r') as input_handle: input_dict = json.load(input_handle) with open(input_dict["scene"]["aircraft"]["test_plane"]["file"], 'r') as airplane_file_handle: airplane_dict = json.load(airplane_file_handle) for key in airplane_dict["wings"]: airplane_dict["wings"][key]["sweep"] = 30 if "v_stab" not in key: airplane_dict["wings"][key]["dihedral"] = 10 airplane_dict["wings"][key].pop("twist", None) airplane_state = input_dict["scene"]["aircraft"].pop("test_plane") state = airplane_state.get("state", {}) control_state = airplane_state.get("control_state", {}) # Load scene scene = MX.Scene(input_dict) scene.add_aircraft("test_plane", airplane_dict, state=state, control_state=control_state) # Check wing tip locations correct_locations = { "main_wing_left": [ -4.618802153517006 / 2, -7.878462024097664 / 2, -1.3891854213354426 / 2 ], "main_wing_right": [ -4.618802153517006 / 2, 7.878462024097664 / 2, -1.3891854213354426 / 2 ], "h_stab_left": [-4.1547005383792515, -1.9696155060244158, -0.3472963553338607], "h_stab_right": [-4.1547005383792515, 1.9696155060244158, -0.3472963553338607], "v_stab_right": [-4.1547005383792515, 0, -2.1] } wing_dict = scene._airplanes["test_plane"].wing_segments for key in wing_dict: tip_loc = wing_dict[key].get_tip_loc() print(tip_loc[2]) assert np.allclose(tip_loc.flatten(), correct_locations[key], rtol=0, atol=1e-10)
def test_two_aircraft(): # Tests that two aircraft flying side by side are properly modelled # Load input with open(input_file, 'r') as input_handle: input_dict = json.load(input_handle) with open(input_dict["scene"]["aircraft"]["test_plane"]["file"], 'r') as airplane_file_handle: airplane_dict = json.load(airplane_file_handle) input_dict["solver"]["type"] = "nonlinear" airplane_state = input_dict["scene"]["aircraft"].pop("test_plane") state = airplane_state.get("state", {}) control_state = airplane_state.get("control_state", {}) # Load scene scene = MX.Scene(input_dict) state["orientation"] = [np.sqrt(2) / 2, 0, 0, np.sqrt(2) / 2] scene.add_aircraft("test_plane_0", airplane_dict, state=state, control_state=control_state) state["position"] = [25, 0, 0] scene.add_aircraft("test_plane_1", airplane_dict, state=state, control_state=control_state) FM = scene.solve_forces(verbose=True) # Since the aircraft are mirror images, their forces should be the same, with some being opposite assert abs(FM["test_plane_0"]["total"]["FL"] - FM["test_plane_1"]["total"]["FL"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["FD"] - FM["test_plane_1"]["total"]["FD"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["FS"] + FM["test_plane_1"]["total"]["FS"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["Fx"] - FM["test_plane_1"]["total"]["Fx"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["Fy"] + FM["test_plane_1"]["total"]["Fy"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["Fz"] - FM["test_plane_1"]["total"]["Fz"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["Mx"] + FM["test_plane_1"]["total"]["Mx"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["My"] - FM["test_plane_1"]["total"]["My"]) < 1e-6 assert abs(FM["test_plane_0"]["total"]["Mz"] + FM["test_plane_1"]["total"]["Mz"]) < 1e-6
def worker(input, output): my_scene = MX.Scene("F16_input.json") for args in iter(input.get, 'STOP'): t0 = time.time() my_scene.set_aircraft_state(state={ "alpha": args[0], "beta": args[1], "velocity": 222.5211 }) result = my_scene.solve_forces() print(time.time() - t0) output.put(result)
def test_jackson_compare(): # Tests that the circulation distribution for a swept wing matches Jackson's result (quickly becoming obsolete...) return # This test is obsolete # Inputs input_dict = {"solver": {"type": "scipy_fsolve"}, "scene": {}} airplane_dict = { "weight": 10, "airfoils": { "NACA_0012": { "CLa": 6.907213339669221, "geometry": { "NACA": "0012" } } }, "wings": { "main_wing": { "ID": 1, "side": "both", "is_main": True, "semispan": 2.5, "chord": 1.0, "airfoil": "NACA_0012", "sweep": 45.0, "ac_offset": "kuchemann", "grid": { "N": 20, "reid_corrections": True } } } } # Get results state = {"velocity": 10.0, "alpha": 10.0} scene = MX.Scene(input_dict) scene.add_aircraft("jackson_wing", airplane_dict, state=state) FM = scene.solve_forces(verbose=True, report_by_segment=True, non_dimensional=False) # Check circulation distribution correct_gamma = np.array([ 0.47123536, 1.36936314, 2.16971088, 2.78795243, 3.18301932, 3.41035458, 3.53474218, 3.59736899, 3.62115168, 3.61858063, 3.59673976, 3.56030944, 3.5136121, 3.46215726, 3.41358434, 3.37738807, 3.36088964, 3.35806733, 3.35540463, 3.353645, 3.353645, 3.35540463, 3.35806733, 3.36088964, 3.37738807, 3.41358434, 3.46215726, 3.5136121, 3.56030944, 3.59673976, 3.61858063, 3.62115168, 3.59736899, 3.53474218, 3.41035458, 3.18301932, 2.78795243, 2.16971088, 1.36936314, 0.47123536 ]) assert np.allclose(scene._gamma, correct_gamma)
def test_unspecified_wind(): # Alter input with open(input_file, 'r') as json_handle: input_dict = json.load(json_handle) input_dict["units"] = "SI" scene = MX.Scene(input_dict) for i in range(5): # Test 5 random positions position = np.random.random(3) * 10000 wind = scene._get_wind(position).flatten() assert np.allclose(wind, [0, 0, 0], rtol=0.0, atol=1e-10) == True
def test_unspecified_english_density(): # Alter input with open(input_file, 'r') as json_handle: input_dict = json.load(json_handle) input_dict["units"] = "English" scene = MX.Scene(input_dict) for i in range(5): # Test 5 random positions position = np.random.random(3) * 10000 density = scene._get_density(position) assert np.allclose(density, 0.00237689072965, rtol=0.0, atol=1e-10) == True
def test_control_derivatives(): # Test the calculation of the control derivatives # Load scene scene = MX.Scene(input_file) cont_derivs = scene.aircraft_control_derivatives() assert abs(cont_derivs["test_plane"]["CL,daileron"]) < 1e-10 assert abs(cont_derivs["test_plane"]["CD,daileron"]) < 1e-10 assert abs(cont_derivs["test_plane"]["CS,daileron"] - 0.13409255196609768) < 1e-10 assert abs(cont_derivs["test_plane"]["Cx,daileron"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cy,daileron"] - 0.13409255196609768) < 1e-10 assert abs(cont_derivs["test_plane"]["Cz,daileron"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cl,daileron"] + 0.4829213183114422) < 1e-10 assert abs(cont_derivs["test_plane"]["Cm,daileron"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cn,daileron"] + 0.1173202524037608) < 1e-10 assert abs(cont_derivs["test_plane"]["CL,delevator"] - 1.6795004768670678) < 1e-10 assert abs(cont_derivs["test_plane"]["CD,delevator"] - 0.030957629339379567) < 1e-10 assert abs(cont_derivs["test_plane"]["CS,delevator"] + 2.7500552332993075e-16) < 1e-10 assert abs(cont_derivs["test_plane"]["Cx,delevator"] - 0.02767495056623802) < 1e-10 assert abs(cont_derivs["test_plane"]["Cy,delevator"] + 2.7500552332993075e-16) < 1e-10 assert abs(cont_derivs["test_plane"]["Cz,delevator"] + 1.6795577762381937) < 1e-10 assert abs(cont_derivs["test_plane"]["Cl,delevator"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cm,delevator"] + 4.975416426126367) < 1e-10 assert abs(cont_derivs["test_plane"]["Cn,delevator"] - 1.5931710494786176e-16) < 1e-10 assert abs(cont_derivs["test_plane"]["CL,drudder"]) < 1e-10 assert abs(cont_derivs["test_plane"]["CD,drudder"]) < 1e-10 assert abs(cont_derivs["test_plane"]["CS,drudder"] + 0.6384357546253706) < 1e-10 assert abs(cont_derivs["test_plane"]["Cx,drudder"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cy,drudder"] + 0.6384357546253706) < 1e-10 assert abs(cont_derivs["test_plane"]["Cz,drudder"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cl,drudder"] + 0.1411603229331166) < 1e-10 assert abs(cont_derivs["test_plane"]["Cm,drudder"]) < 1e-10 assert abs(cont_derivs["test_plane"]["Cn,drudder"] - 0.5111158114523209) < 1e-10
def test_all_wing_segments_get_added(): # Tests that all wing segments have been added and are available through # both the tree and the dict. # Load wing segments with open(input_file, 'r') as input_handle: input_dict = json.load(input_handle) with open(input_dict["scene"]["aircraft"]["test_plane"]["file"], 'r') as airplane_file_handle: airplane_dict = json.load(airplane_file_handle) wing_segments = [] wing_segment_sides = [] for key in airplane_dict["wings"]: wing_segments.append(key) wing_segment_sides.append(airplane_dict["wings"][key]["side"]) # Create scene scene = MX.Scene(input_file) # Check for each wing segment in both the tree and the dict wing_dict = scene._airplanes["test_plane"].wing_segments for segment_name, segment_side in zip(wing_segments, wing_segment_sides): if segment_side == "left" or segment_side == "both": name = segment_name + "_left" # Retrieve from dictionary dict_segment = wing_dict[name] # Retrieve from tree tree_segment = scene._airplanes["test_plane"]._get_wing_segment( name) # Make sure these reference the same object assert dict_segment is tree_segment if segment_side == "right" or segment_side == "both": name = segment_name + "_right" # Retrieve from dictionary dict_segment = wing_dict[name] # Retrieve from tree tree_segment = scene._airplanes["test_plane"]._get_wing_segment( name) # Make sure these reference the same object assert dict_segment is tree_segment
def test_compute_variable_swept_dihedral_wing_tip_location(): # Tests the tip of the wing is in the proper location for a wing with # both linearly varying sweep and linearly varying dihedral # Alter input with open(input_file, 'r') as input_handle: input_dict = json.load(input_handle) with open(input_dict["scene"]["aircraft"]["test_plane"]["file"], 'r') as airplane_file_handle: airplane_dict = json.load(airplane_file_handle) for key in airplane_dict["wings"]: airplane_dict["wings"][key]["sweep"] = [[0.0, 0.0], [1.0, 40.0]] if "v_stab" not in key: airplane_dict["wings"][key]["dihedral"] = [[0.0, 0.0], [1.0, 10.0]] airplane_dict["wings"][key].pop("twist", None) airplane_state = input_dict["scene"]["aircraft"].pop("test_plane") state = airplane_state.get("state", {}) control_state = airplane_state.get("control_state", {}) # Load scene scene = MX.Scene(input_dict) scene.add_aircraft("test_plane", airplane_dict, state=state, control_state=control_state) # Check wing tip locations correct_locations = { "main_wing_left": [-1.5270189901562612, -3.979723080181195, -0.3481806534883265], "main_wing_right": [-1.5270189901562612, 3.979723080181195, -0.3481806534883265], "h_stab_left": [-3.7635094950781305, -1.9898615400905975, -0.17409032674416325], "h_stab_right": [-3.7635094950781305, 1.9898615400905975, -0.17409032674416325], "v_stab_right": [-3.7635094950781305, 0, -2.1] } wing_dict = scene._airplanes["test_plane"].wing_segments for key in wing_dict: tip_loc = wing_dict[key].get_tip_loc() assert np.allclose(tip_loc.flatten(), correct_locations[key], rtol=0, atol=1e-10)
def test_specified_SI_density_with_english_units(): # Alter input with open(input_file, 'r') as json_handle: input_dict = json.load(json_handle) input_dict["units"] = "English" input_dict["scene"]["atmosphere"]["rho"] = [1.225, "kg/m^3"] scene = MX.Scene(input_dict) for i in range(5): # Test 5 random positions position = np.random.random(3) * 10000 density = scene._get_density(position) assert np.allclose(density, 0.0023768923675, rtol=0.0, atol=1e-10) == True
def test_constant_airfoil_section_get_lift(): # Tests the lift coefficient is properly given for a constant airfoil section # Load scene scene = MX.Scene(input_file) alphas = np.radians([0, 1, 2]) CLs = [0.0, 0.1122875027563072, 0.2245750055126144] wing_segments = scene._airplanes["test_plane"].wing_segments for alpha, correct_CL in zip(alphas, CLs): for key in wing_segments: N = wing_segments[key].N CL = wing_segments[key].get_cp_CL(np.repeat(alpha, N), 0.0, 0.0) assert np.allclose(CL, correct_CL, rtol=0.0, atol=1e-10)