diff --git a/optvl/optvl_class.py b/optvl/optvl_class.py index 24d55eb2..1bd186ec 100644 --- a/optvl/optvl_class.py +++ b/optvl/optvl_class.py @@ -230,7 +230,7 @@ def __init__( debug: Optional[bool] = False, timing: Optional[bool] = False, ): - """Initalize the python and fortran libary from the given objects + """Initialize the python and fortran library from the given objects Args: geo_file: AVL geometry file @@ -467,8 +467,8 @@ def _init_map_data(self): def _setup_surface_maps(self, surf_name: str, idx_surf: int, num_sec: int): """Used by the init_map_data and load_input_dict functions to generate which slices of the Fortran array for a - given geometry, panneling, control surface, or design variable correspond to the given surface. This data is - stored the surf_geom_to_fort_var dictionary. + given geometry, paneling, control surface, or design variable correspond to the given surface. This data is + stored in the surf_geom_to_fort_var dictionary. Args: surf_name: The name of the surface @@ -562,7 +562,7 @@ def _setup_surface_maps(self, surf_name: str, idx_surf: int, num_sec: int): def _setup_body_maps(self, body_name: str, idx_body: int): """Used by the init_map_data and load_input_dict functions to generate which slices of the Fortran array for a - given geometry or discretization variable correspond to the given body. This data is stored the + given geometry or discretization variable correspond to the given body. This data is stored in the body_param_to_fort_var dictionary. Args: @@ -582,7 +582,7 @@ def _setup_body_maps(self, body_name: str, idx_body: int): def _setup_section_maps(self, surf_name: str, idx_surf: int, num_sec: int, nasec_arr: np.ndarray): """Used by the init_map_data and load_input_dict functions to generate which slices of the Fortran array for a - given section geometry variable correspond to the given surface and section. This data is stored the + given section geometry variable correspond to the given surface and section. This data is stored in the surf_section_geom_to_fort_var dictionary. Args: @@ -628,7 +628,7 @@ def load_input_dict(self, input_dict: dict, pre_check: bool = True, post_check: Args: input_dict: input dictionary in optvl format pre_check: perform additional verification of the user's input dictionary before loading into AVL - post_check: verify certain inputs values are correctly reflected in the Fortran layer + post_check: verify certain input values are correctly reflected in the Fortran layer """ # Initialize Variables and Counters @@ -1172,7 +1172,7 @@ def set_mesh(self, idx_surf: int, mesh: np.ndarray, flatten:bool=True, update_nv Args: idx_surf (int): the surface to apply the mesh to mesh (np.ndarray): XYZ mesh array (nx,ny,3) - flatten (bool): Should OptVL flatten the mesh when placing vorticies and control points + flatten (bool): Should OptVL flatten the mesh when placing vortices and control points update_nvs (bool): Should OptVL update the number of spanwise elements for the given mesh update_nvc (bool): Should OptVL update the number of chordwise elements for the given mesh """ @@ -1208,7 +1208,6 @@ def set_mesh(self, idx_surf: int, mesh: np.ndarray, flatten:bool=True, update_nv def get_mesh(self, idx_surf: int, concat_dup_mesh: bool = False): """Returns the current set mesh coordinates from AVL as a numpy array. - Note this is intended for Args: idx_surf (int): the surface to get the mesh for @@ -1260,7 +1259,7 @@ def set_section_naca(self, isec: int, isurf: int, nasec: int, naca: str, xfminma isec: section number to set the airfoil mesh isurf: surface number to set the airfoil mesh nasec: number of points to evaluate the interpolated camber line and thickness curves at - naca: 4-digit naca specificaion as a string + naca: 4-digit naca specification as a string xfminmax: length 2 array with the min and max x/c to slice the airfoil """ @@ -1311,7 +1310,7 @@ def set_section_coordinates( isurf: surface number to set the airfoil mesh nasec: number of points to evaluate the interpolated camber line and thickness curves at x: airfoil x-coordinate array - y: airfoil y-coodinate array + y: airfoil y-coordinate array xfminmax: length 2 array with the min and max x/c to slice the airfoil storecoords: store the raw input coordinates in common block """ @@ -1335,10 +1334,10 @@ def set_body_coordinates(self, ibod: int, nasec: int, x: np.ndarray, y: np.ndarr Args: - ibod: body number to set the outer mold line too + ibod: body number to set the outer mold line to nasec: number of points to evaluate the interpolated camber line and thickness curves at x: oml x-coordinate array - y: oml y-coodinate array + y: oml y-coordinate array xfminmax: length 2 array with the min and max x/c to slice the oml storecoords: store the raw input coordinates in common block """ @@ -1478,16 +1477,17 @@ def execute_run(self, tol: float = 0.00002): """Run the analysis (equivalent to the AVL command `x` in the OPER menu) Args: - tol: the tolerace of the Newton solver used for triming the aircraft + tol: the tolerance of the Newton solver used for trimming the aircraft """ self.set_avl_fort_arr("CASE_R", "EXEC_TOL", tol) self.avl.oper() def set_variable(self, var: str, val: float): - """set a variable for the run case (equivalent to setting a variable in AVL's OPER menu) + """Set a variable for the run case (equivalent to setting a variable in AVL's OPER menu) + Args: - var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. - val: target value of `con_var` + var: variable to be set ["alpha", "beta", "roll rate", "pitch rate", "yaw rate"] or any control surface. + val: target value of `var` """ avl_variables = { "alpha": ("CASE_R", "ALFA"), @@ -1532,11 +1532,12 @@ def set_variable(self, var: str, val: float): # set the contraint value so that the set value is used in analysis self.set_avl_fort_arr("CASE_R", "CONVAL", val, (self.conval_idx_dict[var],)) - def get_variable(self, var: str): - """set a variable for the run case (equivalent to setting a variable in AVL's OPER menu) + def get_variable(self, var: str, inRadians: bool = False): + """Get a variable for the run case (equivalent to reading a variable in AVL's OPER menu) + Args: - var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. - val: target value of `con_var` + var: variable to retrieve ["alpha", "beta", "roll rate", "pitch rate", "yaw rate"] or any control surface. + inRadians: if True, return alpha and beta in radians instead of degrees. Roll, pitch, and yaw rates are always dimensionless. """ avl_variables = { "alpha": ("CASE_R", "ALFA"), @@ -1559,6 +1560,10 @@ def get_variable(self, var: str): "yaw rate": 2 / bref, } + if inRadians: + vars_factors["alpha"] = 1.0 + vars_factors["beta"] = 1.0 + # Check that the variable is valid if var in avl_variables: # save the name of the avl_var @@ -1579,9 +1584,9 @@ def set_constraint(self, var: str, con_var: str, val: float): """Set the constraints on the analysis case (equivalent to setting a constraint in AVL's OPER menu) Args: - var: variable to be constrained ["alpha"", "beta"", "roll rate", "pitch rate", "yaw rate"] or any control surface. + var: variable to be constrained ["alpha", "beta", "roll rate", "pitch rate", "yaw rate"] or any control surface. val: target value of `con_var` - con_var: variable output that needs to be constrained. It could be any value for `var` plus ["CL", "CY", "Cl", "Cm", "Cn"]. If None, than `var` is also the `con_var` + con_var: variable output that needs to be constrained. It could be any value for `var` plus ["CL", "CY", "Cl", "Cm", "Cn"]. If None, then `var` is also the `con_var` """ avl_variables = { @@ -1635,7 +1640,7 @@ def set_constraint(self, var: str, con_var: str, val: float): self.avl.conset(avl_var, f"{avl_con_var} {val} \n") def set_trim_condition(self, variable: str, val: float): - """Set a variable of the trim condition (analogus to the AVL's C1 command from the OPER menu) + """Set a variable of the trim condition (analogous to the AVL's C1 command from the OPER menu) Args: variable: variable to be set. Options are ["bankAng", "CL", "velocity", "mass", "dens", "G", "X cg","Y cg","Z cg"] @@ -1666,7 +1671,7 @@ def get_total_forces(self) -> Dict[str, float]: """Get the aerodynamic data for the last run case and return it as a dictionary. Returns: - Dict[str, float]: Dictionary of aerodynamic data. The keys the aerodyanmic coefficients. + Dict[str, float]: Dictionary of aerodynamic data. The keys are the aerodynamic coefficients. """ total_data = {} @@ -1681,10 +1686,10 @@ def get_total_forces(self) -> Dict[str, float]: return total_data def get_body_forces(self) -> Dict[str, float]: - """Get the aerodynamic data for the last run case and return it as a dictionary. + """Get the aerodynamic force data for each body from the last run case. Returns: - Dict[str, float]: Dictionary of aerodynamic data. The keys the aerodyanmic coefficients. + Dict[str, float]: Dictionary of aerodynamic data. The keys are the aerodynamic coefficients. """ body_data = {} @@ -1708,7 +1713,7 @@ def get_control_stab_derivs(self) -> Dict[str, float]: for the current analysis run Returns: - stab_deriv_dict: The dictionary of control surface derivatives, d{force coefficent}/d{control surface}. + stab_deriv_dict: The dictionary of control surface derivatives, d{force coefficient}/d{control surface}. """ deriv_data = {} @@ -1725,7 +1730,7 @@ def get_control_stab_derivs(self) -> Dict[str, float]: return deriv_data def get_stab_derivs(self) -> Dict[str, float]: - """gets the stability derivates after an analysis run + """Gets the stability derivatives after an analysis run Returns: stab_deriv_dict: Dictionary of stability derivatives. @@ -1739,10 +1744,10 @@ def get_stab_derivs(self) -> Dict[str, float]: return deriv_data def get_body_axis_derivs(self) -> Dict[str, float]: - """gets the body-axis derivates after an analysis run + """Gets the body-axis derivatives after an analysis run Returns: - body_deriv_dict: Dictionary of stability derivatives. + body_deriv_dict: Dictionary of body-axis derivatives. """ deriv_data = {} @@ -1773,11 +1778,11 @@ def set_reference_data(self, ref_data: Dict[str, float], set_default_value:bool return ref_data def get_avl_fort_arr(self, common_block: str, variable: str, slicer: Optional[slice] = None) -> np.ndarray: - """Get data from the Fortran level common block data structure. see AVL.INC for all availible variables + """Get data from the Fortran level common block data structure. See AVL.INC for all available variables Args: common_block: Name of the common block of the variable like `CASE_R` - variable: Name of the variable to retrive + variable: Name of the variable to retrieve slicer: slice applied to the common block variable to return a subset of the data. i.e. (100) or slice(2, 5) Returns: @@ -1806,11 +1811,11 @@ def get_avl_fort_arr(self, common_block: str, variable: str, slicer: Optional[sl return val def set_avl_fort_arr(self, common_block: str, variable: str, val: float, slicer: Optional[slice] = None) -> None: - """Set data from the Fortran level common block data structure. see AVL.INC for all availible variables + """Set data from the Fortran level common block data structure. See AVL.INC for all available variables Args: common_block: Name of the common block of the variable like `CASE_R` - variable: Name of the variable to retrive + variable: Name of the variable to retrieve val: value to set, which can be a numpy array slicer: slice applied to the common block variable to return a subset of the data. i.e. (100) or slice(2, 5) @@ -1853,7 +1858,7 @@ def set_avl_fort_arr(self, common_block: str, variable: str, val: float, slicer: return def get_surface_forces(self) -> Dict[str, Dict[str, float]]: - """Returns the force data from each surface (including mirriored surfaces) + """Returns the force data from each surface (including mirrored surfaces) Returns: surf_data_dict: a dictionary of surface data where the first key is the surface and the second is the force coefficient @@ -1881,7 +1886,7 @@ def get_surface_forces(self) -> Dict[str, Dict[str, float]]: def get_parameter(self, param_key: str) -> float: """ - Analogous to ruinont Modify parameters for the OPER menu to view parameters. + Analogous to the Modify parameters (M) command from the OPER menu in AVL, but for reading parameters. Args: param_key: the name of the parameter to return @@ -1970,7 +1975,7 @@ def get_control_deflections(self) -> Dict[str, float]: return def_dict def get_control_deflection(self, con_surf) -> Dict[str, float]: - """get the deflections of the control surfaces + """Get the deflection of the specified control surface Returns: val: deflection of control surface @@ -1985,10 +1990,11 @@ def get_control_deflection(self, con_surf) -> Dict[str, float]: return val def set_control_deflection(self, con_surf, val) -> Dict[str, float]: - """set the deflections of the control surfaces + """Set the deflection of a control surface - args: - con_surf : Name or D value (D1, D2, etc.) of the control surface + Args: + con_surf: Name or D value (D1, D2, etc.) of the control surface + val: deflection value to set """ con_surf_names = list(self.con_surf_to_dindex.keys()) con_surf_dindex = list(self.dindex_to_con_surf.keys()) @@ -2005,9 +2011,9 @@ def set_control_deflection(self, con_surf, val) -> Dict[str, float]: self.set_avl_fort_arr("CASE_R", "DELCON", val, slicer=(idx_con_surf,)) def set_control_deflections(self, def_dict: Dict[str, float]): - """get the deflections of all the control surfaces + """Set the deflections of all the control surfaces - args: + Args: def_dict: dictionary of control surfaces as the keys and deflections as the values """ control_surfaces = self.get_control_names() @@ -2020,7 +2026,7 @@ def get_hinge_moments(self) -> Dict[str, float]: """Get the hinge moments from the fortran layer and return them as a dictionary Returns: - hinge_moments: array of control surface moments. The order the control surfaces are declared are the indices, + hinge_moments: dictionary of control surface hinge moments keyed by control surface name """ hinge_moments = {} @@ -2173,7 +2179,7 @@ def get_eigenvalues(self) -> np.ndarray: return eig_vals def get_eigenvectors(self) -> np.ndarray: - """After running an eigenmode calculation, this function will return the eigenvalues in the order used by AVL + """After running an eigenmode calculation, this function will return the eigenvectors in the order used by AVL Returns: eig_vec: 2D array of eigen vectors @@ -2199,13 +2205,13 @@ def get_system_matrix(self, in_body_axis=False) -> np.ndarray: return Asys def get_system_matrices(self, in_body_axis=False) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: - """returns the A,B, and R system matrices used in amode.f - - args: + """Returns the A, B, and R system matrices used in amode.f + + Args: in_body_axis: apply the sign changes to the matrix to put it in the body axis - + Returns: - Asys: 2D array representing the system matrix for the eigen value analysis + Asys: 2D array representing the system matrix for the eigenvalue analysis Bsys: 2D array representing the system matrix for control surfaces Rsys: 1D array representing the RHS of the dynamics equation """ @@ -2284,10 +2290,10 @@ def get_control_names(self) -> List[str]: return control_names def get_design_var_names(self) -> List[str]: - """Get the names of the design_var surfaces + """Get the names of the design variables Returns: - design_var_names: list of design_var surface names + design_var_names: list of design variable names """ fort_names = self.get_avl_fort_arr("CASE_C", "GNAME") design_var_names = self._fort_char_array_to_str_list(fort_names) @@ -2297,7 +2303,7 @@ def get_surface_names(self, remove_dublicated: Optional[bool] = False) -> List[s """Get the surface names from the geometry Args: - remove_dublicated: remove the surface that were created by duplication about symmetry planes + remove_dublicated: remove the surfaces that were created by duplication about symmetry planes Returns: surf_names: list of surface names @@ -2321,7 +2327,7 @@ def get_body_names(self, remove_dublicated: Optional[bool] = False) -> List[str] """Get the body names from the geometry Args: - remove_dublicated: remove the body that were created by duplication about symmetry planes + remove_dublicated: remove the bodies that were created by duplication about symmetry planes Returns: body_names: list of body names @@ -2368,12 +2374,12 @@ def get_con_surf_param(self, surf_name: str, idx_sec: int, param: str) -> np.nda return param def __get_des_var_param(self, surf_name: str, idx_sec: int, param: str) -> np.ndarray: - """Returns the parameters that define the control surface. Can also get design variables (AVL). + """Returns the parameters that define a design variable. Args: - surf_name: the name of the surface containing the control surface - idx_sec: the section index of the control surface data - param: control surface parameter to get + surf_name: the name of the surface containing the design variable + idx_sec: the section index of the design variable data + param: design variable parameter to get Returns: parm: parameter value @@ -2464,12 +2470,12 @@ def get_surface_param(self, surf_name: str, param: str) -> np.ndarray: return copy.deepcopy(param) # return the value of the array, but not a reference to avoid sideffects def set_surface_param(self, surf_name: str, param: str, val: float, update_geom: bool = True): - """Set a parameter of a specified surface. Supports setting params related to geometry and panelling. + """Set a parameter of a specified surface. Supports setting params related to geometry and paneling. Section geometry can be directly set here but this is not recommended. Use set_section_coordinates instead. Args: surf_name: the surface containing the parameter - param: the surface parameter to return. Could be either geometric or paneling + param: the surface parameter to set. Could be either geometric or paneling val: value to set update_geom: flag to update the geometry after setting """ @@ -2539,7 +2545,7 @@ def get_surface_params( include_des_vars: bool = False, include_airfoils: bool = False, ) -> Dict[str, Dict[str, Any]]: - """Get all the surface level parameters for each suface + """Get all the surface level parameters for each surface Args: include_geom: flag to include geometry data in the output. The data is ["scale", "translate", "angle", "xles", "yles", "zles", "chords", "aincs", "clcdsec", "claf"] @@ -2548,7 +2554,7 @@ def get_surface_params( include_con_surf: flag to include control surface and design variable data in the output. This is data like the hinge vector and gain. include_airfoils: flag to include airfoil file data in the output - Return: + Returns: surf_data: Nested dictionary where the 1st key is the surface name and the 2nd key is the parameter. """ surf_data = {} @@ -2686,7 +2692,7 @@ def get_body_param(self, body_name: str, param: str) -> np.ndarray: Returns: - val: the val of parameter of the body + val: the value of the parameter of the body """ body_names = self.get_body_names() @@ -2720,7 +2726,7 @@ def set_body_param(self, body_name: str, param: str, val, update_geom: bool = Tr Args: body_name: the body containing the parameter - param: the surface parameter to return. Could be either geometric or paneling + param: the body parameter to set. Could be either geometric or paneling val: value to set update_geom: flag to update the geometry after setting """ @@ -2802,7 +2808,7 @@ def get_body_params( return body_data def set_body_params(self, body_data: Dict[str, Dict[str, Any]]): - """Set the give body data of the current geometry. + """Set the given body data of the current geometry. Args: body_data: Nested dictionary where the 1st key is the body name and the 2nd key is the parameter. @@ -3135,12 +3141,11 @@ def _write_data(key_list: List[str], newline: bool = True): # region --- Utility functions def get_num_surfaces(self) -> int: - """Returns the number of surface including duplicated + """Returns the number of surfaces including duplicated surfaces Returns: val: number of surfaces """ - """Get the number of surfaces in the geometry""" return self.get_avl_fort_arr("CASE_I", "NSURF") def get_surface_index(self, surf_name: str) -> int: @@ -3176,7 +3181,7 @@ def get_num_sections(self, surf_name: str) -> int: surf_name: name of the surface Returns: - nsec: numer of sections + nsec: number of sections """ idx_surf = self.get_surface_index(surf_name) slice_idx_surf = (idx_surf,) @@ -3206,7 +3211,7 @@ def get_mesh_size(self) -> int: return int(self.get_avl_fort_arr("CASE_I", "NVOR")) def get_mesh_data(self) -> Dict[str, int]: - """Get the number of vortices in the mesh + """Get mesh size data (bodies, surfaces, strips, vortices, and variables) Returns: mesh_data : dict @@ -3224,8 +3229,8 @@ def get_mesh_data(self) -> Dict[str, int]: return mesh_data def _str_to_fort_str(self, py_string, num_max_char): - """Setting arrays of strings in Fortran can be kinda nasty. This - takes a strings and returns the char array. + """Setting arrays of strings in Fortran is complex. This + takes a string and returns the char array. """ arr = np.zeros((), dtype=f"|S{num_max_char}") @@ -3239,8 +3244,8 @@ def _str_to_fort_str(self, py_string, num_max_char): return arr def _str_to_fort_char_array(self, py_string, num_max_char): - """Setting arrays of strings in Fortran can be kinda nasty. This - takes a strings and returns the char array. + """Setting arrays of strings in Fortran is complex. This + takes a string and returns the char array. """ arr = np.zeros(1, dtype=f"|S{num_max_char}") @@ -3254,8 +3259,8 @@ def _str_to_fort_char_array(self, py_string, num_max_char): return arr def _str_list_to_fort_char_array(self, strList, num_max_char): - """Setting arrays of strings in Fortran can be kinda nasty. This - takes a list of strings and returns the array. + """Setting arrays of strings in Fortran is complex. This + takes a list of strings and returns the char array. """ arr = np.zeros((len(strList), num_max_char), dtype="str") @@ -3834,7 +3839,7 @@ def _execute_jac_vec_prod_fwd( step: Step size to use for the FD mode Returns: - func_seeds: force coifficent AD seeds + func_seeds: force coefficient AD seeds res_seeds: residual AD seeds consurf_derivs_seeds: Control surface derivatives AD seeds stab_derivs_seeds: Stability derivatives AD seeds @@ -4143,7 +4148,7 @@ def execute_run_sensitivities( funcs: force coefficients to compute the sensitivities with respect to stab_derivs: stability derivatives to compute the sensitivities with respect to body_axis_derivs: body axis derivatives to compute the sensitivities with respect to - consurf_derivs: control surface derivates to compute the sensitivities with respect to + consurf_derivs: control surface derivatives to compute the sensitivities with respect to print_timings: flag to print timing information Returns: @@ -4570,7 +4575,7 @@ def plot_geom(self, axes=None, body_color="magenta"): """Generate a matplotlib plot of geometry Args: - axes: Matplotlib axis object to add the plots too. If none are given, the axes will be generated. + axes: Matplotlib axis object to add the plots to. If none are given, the axes will be generated. body_color: Color to use for plotting body geometry (default: 'magenta') """ @@ -4781,12 +4786,12 @@ def plot_geom_3d(self, axes=None, plot_avl_mesh = True, plot_direct_mesh = False By default the flat version of the mesh that satisfies AVL's VLM assumptions is plotted. This is either the mesh that comes as a result of AVL's standard geometry specification system or the custom user assigned mesh after it has undergone the transformation needed to flatten it to - satify the VLM assumptions. There is also an option to overlay the directly assigned mesh. This will + satisfy the VLM assumptions. There is also an option to overlay the directly assigned mesh. This will plot user assigned mesh as is with no modifications. Args: - axes: Matplotlib axis object to add the plots too. If none are given, the axes will be generated. - plot_avl_mesh: If True the AVL flattenned mesh is plotted on the axis + axes: Matplotlib axis object to add the plots to. If none are given, the axes will be generated. + plot_avl_mesh: If True the AVL flattened mesh is plotted on the axis plot_direct_mesh: If True the user assigned mesh will be plotted as is """