-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add the automatic differentiation multibody solver based on JAX #305
base: develop
Are you sure you want to change the base?
Changes from 6 commits
104eeb8
a6f524d
6c86c29
5a9ad29
545395f
5b9765e
55f20eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,7 +145,8 @@ def run(self): | |
"openpyxl>=3.0.10", | ||
"lxml>=4.4.1", | ||
"PySocks", | ||
"PyYAML" | ||
"PyYAML", | ||
"jax", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added JAX as a new dependency during install |
||
], | ||
extras_require={ | ||
"docs": [ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,11 +193,6 @@ def generate_zeta_timestep_info(self, structure_tstep, aero_tstep, beam, setting | |
else: | ||
global_node_in_surface[i_surf].append(i_global_node) | ||
|
||
# master_elem, master_elem_node = beam.master[i_elem, i_local_node, :] | ||
# if master_elem < 0: | ||
# master_elem = i_elem | ||
# master_elem_node = i_local_node | ||
|
||
# find the i_surf and i_n data from the mapping | ||
i_n = -1 | ||
ii_surf = -1 | ||
|
@@ -270,15 +265,28 @@ def generate_zeta_timestep_info(self, structure_tstep, aero_tstep, beam, setting | |
raise NotImplementedError(str(self.data_dict['control_surface_type'][i_control_surface]) + | ||
' control surfaces are not yet implemented') | ||
|
||
|
||
# add sweep for aerogrid warping in constraint defintition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New code for dynamically sweeping the aero grid. This shouldn't impact any existing cases as it will ignore it if the warp factor parameter does not exist. |
||
# if no constraint_xx.aerogrid warp factor is provided, this will be ignored | ||
ang_warp = 0. | ||
if structure_tstep.mb_dict is not None: | ||
if structure_tstep.mb_prescribed_dict is not None: | ||
for i_constraint in range(structure_tstep.mb_dict['num_constraints']): | ||
try: | ||
cst_name = f"constraint_{i_constraint:02d}" | ||
ctrl_id = structure_tstep.mb_dict[cst_name]['controller_id'].decode('UTF-8') | ||
f_warp = structure_tstep.mb_dict[cst_name]['aerogrid_warp_factor'][i_elem, i_local_node] | ||
ang_z = structure_tstep.mb_prescribed_dict[ctrl_id]['delta_psi'][2] | ||
ang_warp += f_warp * ang_z | ||
except KeyError: | ||
continue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, why is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The constraints here are input as dictionaries and have different key-value pairs depending on their functionality (hinge axis, node number etc.). Warping the aerodynamic grid will occur here if a constraint has both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Is the logic of it along this line? if 'controller_id' in structure_tstep.mb_dict[cst_name] and 'aerogrid_warp_factor' in structure_tstep.mb_dict[cst_name]:
f_warp = structure_tstep.mb_dict[cst_name]['aerogrid_warp_factor'][i_elem, i_local_node]
ctrl_id = structure_tstep.mb_dict[cst_name]['controller_id'].decode('UTF-8')
ang_z = structure_tstep.mb_prescribed_dict[ctrl_id]['delta_psi'][2]
ang_warp += f_warp * ang_z |
||
|
||
node_info = dict() | ||
node_info['i_node'] = i_global_node | ||
node_info['i_local_node'] = i_local_node | ||
node_info['chord'] = self.data_dict['chord'][i_elem, i_local_node] | ||
node_info['chord'] = self.data_dict['chord'][i_elem, i_local_node] / np.cos(ang_warp) | ||
node_info['eaxis'] = self.data_dict['elastic_axis'][i_elem, i_local_node] | ||
node_info['twist'] = self.data_dict['twist'][i_elem, i_local_node] | ||
node_info['sweep'] = self.data_dict['sweep'][i_elem, i_local_node] | ||
node_info['sweep'] = self.data_dict['sweep'][i_elem, i_local_node] + ang_warp | ||
node_info['M'] = self.dimensions[i_surf, 0] | ||
node_info['M_distribution'] = self.data_dict['m_distribution'].decode('ascii') | ||
node_info['airfoil'] = self.data_dict['airfoil_distribution'][i_elem, i_local_node] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,9 @@ class Polar: | |
|
||
def __init__(self): | ||
|
||
self.cm_interp = None | ||
self.cd_interp = None | ||
self.cl_interp = None | ||
self.table = None | ||
self.aoa_cl0_deg = None | ||
|
||
|
@@ -34,15 +37,11 @@ def initialise(self, table): | |
for ipoint in range(npoints - 1): | ||
if self.table[ipoint, 1] == 0.: | ||
matches.append(self.table[ipoint, 0]) | ||
elif (self.table[ipoint, 1] < 0. and self.table[ipoint + 1, 1] > 0): | ||
# elif ((self.table[ipoint, 1] < 0. and self.table[ipoint + 1, 1] > 0) or | ||
# (self.table[ipoint, 1] > 0. and self.table[ipoint + 1, 1] < 0)): | ||
if (self.table[ipoint, 0] <= 0.): | ||
elif self.table[ipoint, 1] < 0. and self.table[ipoint + 1, 1] > 0: | ||
if self.table[ipoint, 0] <= 0.: | ||
matches.append(np.interp(0, | ||
self.table[ipoint:ipoint+2, 1], | ||
self.table[ipoint:ipoint+2, 0])) | ||
# else: | ||
# print("WARNING: Be careful negative camber airfoil not supported") | ||
|
||
iaoacl0 = 0 | ||
aux = np.abs(matches[0]) | ||
|
@@ -62,7 +61,7 @@ def get_coefs(self, aoa_deg): | |
cd = self.cd_interp(aoa_deg) | ||
cm = self.cm_interp(aoa_deg) | ||
|
||
return cl, cd, cm | ||
return cl[0], cd[0], cm[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed one of the pesky errors converting an array to a scalar during the unit test - this seems to work fine. |
||
|
||
def get_aoa_deg_from_cl_2pi(self, cl): | ||
|
||
|
@@ -116,7 +115,7 @@ def get_cdcm_from_cl(self, cl): | |
cd = np.interp(cl, self.table[i:i+2, 1], self.table[i:i+2, 2]) | ||
cm = np.interp(cl, self.table[i:i+2, 1], self.table[i:i+2, 3]) | ||
|
||
return cd, cm | ||
return float(cd), float(cm) | ||
|
||
|
||
def interpolate(polar1, polar2, coef=0.5): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New documentation - should be general for both multibody implementations.