diff --git a/examples/run_opt_camber_ga.py b/examples/run_opt_camber_ga.py index fb7ac10..e3b8e42 100644 --- a/examples/run_opt_camber_ga.py +++ b/examples/run_opt_camber_ga.py @@ -324,10 +324,47 @@ def main(): baseline_coeffs = np.array([0.02, 0.0]) baseline_cambers = quadratic_camber_distribution(baseline_coeffs, Y_POSITIONS) incidences = linear_incidence_distribution(Y_POSITIONS) - create_avl_file_with_naca_airfoils(baseline_cambers, incidences, TEMP_AVL_FILE) + + geom_dict = { + "title": "AIRCRAFT", # Aicraft name (MUST BE SET) + "mach": 0.0, # Reference Mach number + "iysym": 0, # y-symmetry settings + "izsym": 0, # z-symmetry settings + "zsym": 0.0, # z-symmetry plane + "Sref": 0.8127, # Reference planform area + "Cref": 0.2286, # Reference chord area + "Bref": 3.556, # Reference span length + "XYZref": np.array([0.0, 0, 0]), # Reference x,y,z position + "CDp": 0.0, # Reference profile drag adjustment + "surfaces": { # dictionary of surface dictionaries + "Wing": { + # General + "num_sections": NUM_SECTIONS, # number of sections in surface + "num_controls": np.array([0]*NUM_SECTIONS), # number of control surfaces assocaited with each section (in order) + "num_design_vars": np.array([0]*NUM_SECTIONS), # number of AVL design variables assocaited with each section (in order) + "component": 1, # logical surface component index (for grouping interacting surfaces, see AVL manual) + "yduplicate": 0.0, # surface is duplicated over the ysymm plane + "xles": np.zeros(NUM_SECTIONS), # leading edge cordinate vector(x component) + "yles": np.linspace(0, Y_TIP, NUM_SECTIONS), # leading edge cordinate vector(y component) + "zles": np.zeros(NUM_SECTIONS), # leading edge cordinate vector(z component) + "chords": np.ones(NUM_SECTIONS)*0.2286, # chord length vector + "aincs": incidences, # incidence angle vector + # NACA + 'naca' : np.array(['2412']*NUM_SECTIONS), # 4-digit NACA airfoil + # Paneling + "nchordwise": 8, # number of chordwise horseshoe vortice s placed on the surface + "cspace": 1.0, # chordwise vortex spacing parameter + "nspan": 20, # number of spanwise horseshoe vortices placed on the entire surface + "sspace": -2.0, # spanwise vortex spacing parameter for entire surface + "nspans": np.array([5]*NUM_SECTIONS), # number of spanwise elements vector + "sspaces": np.array([3.0]*NUM_SECTIONS), # spanwise spacing vector (for each section) + "use surface spacing": 1, # surface spacing set for the entire surface (known as LSURFSPACING in AVL) + }, + } + } # Initialize solver ONCE - this will be reused throughout optimization - ovl = OVLSolver(geo_file=TEMP_AVL_FILE, debug=DEBUG) + ovl = OVLSolver(input_dict=geom_dict, debug=DEBUG) ovl.set_constraint('alpha', None, TRIM_AOA) ovl.set_parameter('velocity', TRIM_VELOCITY) ovl.execute_run() diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 109b89b..293e0d0 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -640,22 +640,23 @@ def get_types_from_blk(common_blk): if last_char == "C": return str elif last_char == "R": - return (float, np.float64) + return (np.float64, float) elif last_char == "I": - return (int, np.int32) + return (np.int32, int) elif last_char == "L": return (bool, int, np.int32) else: raise ValueError(f"type not able to be infered from common block {common_blk}") - def check_type(key, avl_vars, given_val): - """Checks the type for a given AVL Fortran Common Block var against a given value + def check_type(key, avl_vars, given_val, cast_type=True): + """Checks the type for a given AVL Fortran Common Block var against a given value. + If the type can be cast into the correct type then it is and returned Args: key: OptVL input variable dictionary key avl_vars: AVL Common Block variable name array given_val: Input value to check type against - + cast_type: Flag to cast the type into the required type if possible """ # get the type that it should be expected_type = get_types_from_blk(avl_vars[0]) @@ -687,15 +688,24 @@ def check_type(key, avl_vars, given_val): # check that the type of the array matches the expectation if not isinstance(given_val.flatten()[0], expected_type): - raise TypeError( - f"Variable {key} is an array of type {given_val.dtype} but expected {expected_type}" - ) + if cast_type and np.can_cast(given_val.dtype, expected_type[0], casting='same_kind'): + given_val = given_val.astype(np.dtype(expected_type[0])) + else: + raise TypeError( + f"Variable {key} is an array of type {given_val.dtype} but expected {expected_type}" + ) else: # check the type of the scaler if not isinstance(given_val, expected_type): - raise TypeError( - f"Variable {key} is a scalar of type {type(given_val)} but expected {expected_type}" - ) + if cast_type and np.can_cast(given_val.dtype, expected_type[0], casting='same_kind'): + given_val = np.dtype(expected_type[0]).type(given_val) + else: + raise TypeError( + f"Variable {key} is a scalar of type {type(given_val)} but expected {expected_type}" + ) + + + return given_val # Set AVL header variables # CDp is the only optional input for the AVL header @@ -710,7 +720,7 @@ def check_type(key, avl_vars, given_val): else: val = input_dict[key] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val) @@ -829,7 +839,7 @@ def check_type(key, avl_vars, given_val): else: val = surf_dict[key] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val, slicer=avl_vars[2]) @@ -842,7 +852,7 @@ def check_type(key, avl_vars, given_val): f"OptVL can only have one method of specifing airfoil geometry per surface, found {airfoil_spec_keys} in surface {surf_name}" ) - xfminmax_arr = surf_dict.get("xfminmax", np.array([0.0, 1.0] * num_secs)) + xfminmax_arr = surf_dict.get("xfminmax", np.tile([0.0, 1.0], (num_secs, 1))) num_pts = min(50, self.IBX) # setup for manually specifying coordinates @@ -881,7 +891,7 @@ def check_type(key, avl_vars, given_val): val = surf_dict[key][j] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val, slicer=avl_vars[2]) # 4 digit NACA airfoil specification @@ -946,7 +956,7 @@ def check_type(key, avl_vars, given_val): else: val = surf_dict[key][j] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val, slicer=avl_vars[2]) # --- setup design variables for each section --- @@ -968,7 +978,7 @@ def check_type(key, avl_vars, given_val): else: val = surf_dict[key][j] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val, slicer=avl_vars[2]) # Make the surface @@ -1025,7 +1035,7 @@ def check_type(key, avl_vars, given_val): else: val = body_dict[key] - check_type(key, avl_vars, val) + val = check_type(key, avl_vars, val) self.set_avl_fort_arr(avl_vars[0], avl_vars[1], val, slicer=avl_vars[2]) diff --git a/src/ainput.f b/src/ainput.f index 148c6a8..ae22e95 100644 --- a/src/ainput.f +++ b/src/ainput.f @@ -91,7 +91,6 @@ SUBROUTINE INPUT(LUN,FNAME,FERR) NSEC_B = 0 C NSURF = 0 - NSURFDUPL = 0 NVOR = 0 NSTRIP = 0 C @@ -206,7 +205,6 @@ SUBROUTINE INPUT(LUN,FNAME,FERR) IF(LDUPL(ISURF)) THEN CALL SDUPL(ISURF,YDUPL(ISURF),'YDUP') NSURF = NSURF + 1 - NSURFDUPL = NSURFDUPL + 1 ENDIF C ISURF = 0 @@ -245,7 +243,6 @@ SUBROUTINE INPUT(LUN,FNAME,FERR) IF(LDUPL(ISURF)) THEN CALL SDUPL(ISURF,YDUPL(ISURF),'YDUP') NSURF = NSURF + 1 - NSURFDUPL = NSURFDUPL + 1 ENDIF C ISURF = 0 @@ -331,7 +328,6 @@ SUBROUTINE INPUT(LUN,FNAME,FERR) IF(LDUPL(ISURF)) THEN CALL SDUPL(ISURF,YDUPL(ISURF),'YDUP') NSURF = NSURF + 1 - NSURFDUPL = NSURFDUPL + 1 ENDIF C ISURF = 0 diff --git a/src/amake.f b/src/amake.f index c7dc32b..99874a7 100644 --- a/src/amake.f +++ b/src/amake.f @@ -650,6 +650,12 @@ subroutine update_surfaces() NVOR = 0 ISURF = 1 + + NSURFDUPL = 0 + do ii=1,(NSURF) + if (ldupl(ii)) NSURFDUPL = NSURFDUPL + 1 + enddo + c the iterations of this loop are not independent because we count c up the size information as we make each surface do ii=1,(NSURF-NSURFDUPL)