55
66class MomentCoefficient (om .ExplicitComponent ):
77 """
8- Compute the coefficient of moment (CM) for the entire aircraft.
8+ Compute the coefficient of moment (CM) and moment (M) for the entire aircraft.
99
1010 Parameters
1111 ----------
@@ -34,6 +34,8 @@ class MomentCoefficient(om.ExplicitComponent):
3434
3535 Returns
3636 -------
37+ M[3] : numpy array
38+ The moment around the x-, y-, and z-axes at the cg point.
3739 CM[3] : numpy array
3840 The coefficient of moment around the x-, y-, and z-axes at the cg point.
3941 """
@@ -59,6 +61,7 @@ def setup(self):
5961 self .add_input ("S_ref_total" , val = 1.0 , units = "m**2" , tags = ["mphys_input" ])
6062
6163 self .add_output ("CM" , val = np .ones ((3 )), tags = ["mphys_result" ])
64+ self .add_output ("M" , val = np .ones ((3 )), units = "N*m" , tags = ["mphys_result" ])
6265
6366 self .declare_partials (of = "*" , wrt = "*" )
6467
@@ -112,12 +115,15 @@ def compute(self, inputs, outputs):
112115 # normalize CM
113116 if j == 0 :
114117 self .MAC_wing = MAC
118+ self .S_ref_wing = S_ref
115119
116120 self .M = M
117121
122+ # Output the moment vector
123+ outputs ["M" ] = M
124+
118125 # Compute the normalized CM
119- rho = inputs ["rho" ]
120- outputs ["CM" ] = M / (0.5 * rho * inputs ["v" ] ** 2 * inputs ["S_ref_total" ] * self .MAC_wing )
126+ outputs ["CM" ] = M / (0.5 * inputs ["rho" ] * inputs ["v" ] ** 2 * inputs ["S_ref_total" ] * self .MAC_wing )
121127
122128 def compute_partials (self , inputs , partials ):
123129 cg = inputs ["cg" ]
@@ -128,12 +134,14 @@ def compute_partials(self, inputs, partials):
128134 # Cached values
129135 M = self .M
130136 MAC_wing = self .MAC_wing
137+ S_ref_wing = self .S_ref_wing
131138
139+ # Scaling factor of one over the dynamic pressure times sum of reference areas times the wing MAC
132140 fact = 1.0 / (0.5 * rho * v ** 2 * S_ref_total * MAC_wing )
133141
134- partials ["CM" , "rho" ] = - M * fact ** 2 * 0.5 * v ** 2 * S_ref_total * MAC_wing
135- partials ["CM" , "v" ] = - M * fact ** 2 * rho * v * S_ref_total * MAC_wing
136- partials ["CM" , "S_ref_total" ] = - M * fact ** 2 * 0.5 * rho * v ** 2 * MAC_wing
142+ partials ["CM" , "rho" ] = - M * fact / rho
143+ partials ["CM" , "v" ] = - 2 * M * fact / v
144+ partials ["CM" , "S_ref_total" ] = - M * fact / S_ref_total
137145
138146 partials ["CM" , "cg" ][:] = 0.0
139147
@@ -156,7 +164,8 @@ def compute_partials(self, inputs, partials):
156164 panel_chords = (chords [1 :] + chords [:- 1 ]) * 0.5
157165 MAC = 1.0 / S_ref * np .sum (panel_chords ** 2 * widths )
158166
159- # This transformation is used for multiple derivatives
167+ # This produces a bi-diagonal matrix for the derivative of panel_chords with respect to chords
168+ # This transformation matrix is further used for multiple derivatives later
160169 dpc_dc = np .zeros ((ny - 1 , ny ))
161170 idx = np .arange (ny - 1 )
162171 dpc_dc [idx , idx ] = 0.5
@@ -174,34 +183,72 @@ def compute_partials(self, inputs, partials):
174183 dMAC_dw *= 2.0
175184 dMAC_dS *= 2.0
176185
177- # diff derivs
186+ # Compute the bound vortex(quarter chord) points at mid-panel
178187 pts = (b_pts [:, 1 :, :] + b_pts [:, :- 1 , :]) * 0.5
188+
189+ # Compute the vectors between the cg and the mid-panel bound vortex points
179190 diff = pts - cg
180191
192+ # Compute the cross product of the panel bound vortex vectors from cg and the panel forces
181193 c = np .cross (diff , sec_forces , axis = 2 )
194+
195+ # Compute the spanwise moment vector distribution by summing over each resulting column
182196 moment = np .sum (c , axis = 0 )
183197
198+ # Compute the derviative of the moment vectors(c) with respect to the diff vectors(a) multiplied by -1
184199 dcda = np .zeros ((3 , nx - 1 , ny - 1 , 3 ))
200+
201+ # Compute the derivative wrt to the first element of diff
185202 dcda [0 , :, :, 1 ] = sec_forces [:, :, 2 ]
186203 dcda [0 , :, :, 2 ] = - sec_forces [:, :, 1 ]
204+
205+ # Compute the derivative wrt to the second element of diff
187206 dcda [1 , :, :, 0 ] = - sec_forces [:, :, 2 ]
188207 dcda [1 , :, :, 2 ] = sec_forces [:, :, 0 ]
208+
209+ # Compute the derivative wrt to the third element of diff
189210 dcda [2 , :, :, 0 ] = sec_forces [:, :, 1 ]
190211 dcda [2 , :, :, 1 ] = - sec_forces [:, :, 0 ]
191212
213+ # Compute the derviative of the moment vectors(c) with respect to the sec_forces vectors(b) multiplied by -1
192214 dcdb = np .zeros ((3 , nx - 1 , ny - 1 , 3 ))
215+
216+ # Compute the derivative wrt to the first element of sec_forces
193217 dcdb [0 , :, :, 1 ] = - diff [:, :, 2 ]
194218 dcdb [0 , :, :, 2 ] = diff [:, :, 1 ]
219+
220+ # Compute the derivative wrt to the second element of sec_forces
195221 dcdb [1 , :, :, 0 ] = diff [:, :, 2 ]
196222 dcdb [1 , :, :, 2 ] = - diff [:, :, 0 ]
223+
224+ # Compute the derivative wrt to the third element of sec_forces
197225 dcdb [2 , :, :, 0 ] = - diff [:, :, 1 ]
198226 dcdb [2 , :, :, 1 ] = diff [:, :, 0 ]
199227
228+ # Compute derivative of CM wrt to the sec_forces of the section by reshaping to 3 rows and multiplying by fact.
200229 partials ["CM" , name + "_sec_forces" ] += dcdb .reshape ((3 , 3 * (nx - 1 ) * (ny - 1 ))) * fact
201230
231+ # Compute derivative of M wrt to the sec_forces of the section by reshaping to 3 rows
232+ partials ["M" , name + "_sec_forces" ] += dcdb .reshape ((3 , 3 * (nx - 1 ) * (ny - 1 )))
233+
234+ # Project the derviative of the moment vectors(c) with respect to the diff vectors(a)
235+ # onto the derivative of mid-panel chord distribution wrt to the chord distribution giving the derivative of
236+ # the moment vectors(c) with respect to the chord distribution(dc_dchord). This works because the diff
237+ # vectors are difference between the mid-panel bound vortex(quarter chord) points and cg which is static in this derivative.
238+ # The spanwise component of the mid-panel bound vortex(quarter chord) points have the same derivatrive wrt to the chord
239+ # distribution as the mid-panel chord distribution does wrt the the chord distribution.
202240 dc_dchord = np .einsum ("ijkl,km->ijml" , dcda , dpc_dc )
241+
242+ # Compute the derivative of CM wrt to the bound vortex points(b_pts) by reshaping dc_dchord to three rows
243+ # and multiplying by fact.
203244 partials ["CM" , name + "_b_pts" ] += dc_dchord .reshape ((3 , 3 * (nx - 1 ) * ny )) * fact
204245
246+ # Compute the derivative of M wrt to the bound vortex points(b_pts) by reshaping dc_dchord to three rows
247+ partials ["M" , name + "_b_pts" ] += dc_dchord .reshape ((3 , 3 * (nx - 1 ) * ny ))
248+
249+ # Reduce the derivative of the moment vectors(c) with respect to the diff vectors(a) by summing over all
250+ # chordwise and spanwise panels(j and k). Reduces to a 3x3 matrix for the whole surface by summing over all
251+ # panels.
205252 dcda = np .einsum ("ijkl->il" , dcda )
206253
207254 # If the surface is symmetric, set the x- and z-direction moments
@@ -216,28 +263,62 @@ def compute_partials(self, inputs, partials):
216263 partials ["CM" , name + "_b_pts" ][0 , :] = 0.0
217264 partials ["CM" , name + "_b_pts" ][1 , :] *= 2.0
218265 partials ["CM" , name + "_b_pts" ][2 , :] = 0.0
266+ partials ["M" , name + "_sec_forces" ][0 , :] = 0.0
267+ partials ["M" , name + "_sec_forces" ][1 , :] *= 2.0
268+ partials ["M" , name + "_sec_forces" ][2 , :] = 0.0
269+ partials ["M" , name + "_b_pts" ][0 , :] = 0.0
270+ partials ["M" , name + "_b_pts" ][1 , :] *= 2.0
271+ partials ["M" , name + "_b_pts" ][2 , :] = 0.0
219272 dcda [0 , :] = 0.0
220273 dcda [1 , :] *= 2.0
221274 dcda [2 , :] = 0.0
222275
276+ # Compute the derivative of CM wrt to the cg position which is negative dcda since diff = pts - cg times fact
277+ # Accumlate the derivative over each surface as the total moment vector is sum over all surfaces.
223278 partials ["CM" , "cg" ] -= dcda * fact
224279
280+ # Compute the derivative of M wrt to the cg position which is negative dcda since diff = pts - cg
281+ # Accumlate the derivative over each surface as the total moment vector is sum over all surfaces.
282+ partials ["M" , "cg" ] -= dcda
283+
284+ # Compute the total surface moment vector by summing spanwise
225285 M_j = np .sum (moment , axis = 0 )
226- term = fact / MAC
227- partials ["CM" , name + "_chords" ] = - np .outer (M_j * term , dMAC_dc )
228- partials ["CM" , name + "_widths" ] = - np .outer (M_j * term , dMAC_dw )
229- partials ["CM" , name + "_S_ref" ] = - np .outer (M_j , dMAC_dS * term )
230286
231287 # For first surface, we need to save the deriv results
232288 if j == 0 :
289+ # Compute a term by dividing fact by MAC. Note that MAC is the mean aerodynamic chord for the surface and
290+ # the MAC_wing terms already factored into fact is of the main wing surface
291+ term = fact / MAC
292+
293+ # Compute the derivative of CM wrt to the chord distribution by taking the negative outer product of the
294+ # moment vector(M_j) time the term with the derivative of MAC wrt to the chord distribution. We only do
295+ # this for the main wing since CM only depends on the MAC of the main wing and the chord distribution of
296+ # the main wing is the only chord distribution of all the surfaces that can impact the MAC of the main wing.
297+ partials ["CM" , name + "_chords" ] = - np .outer (M_j * term , dMAC_dc )
298+
299+ # Compute the derivative of CM wrt to the width distribution by taking the negative outer product of the
300+ # moment vector(M_j) time the term with the derivative of MAC wrt to the width distribution. We only do
301+ # this for the main wing since CM only depends on the MAC of the main wing and the panel width distribution of
302+ # the main wing is the only panel width distribution of all the surfaces that can impact the MAC of the main wing.
303+ partials ["CM" , name + "_widths" ] = - np .outer (M_j * term , dMAC_dw )
304+
305+ # Compute the derivative of CM wrt to the surface S_ref by taking the negative outer product of the
306+ # moment vector(M_j) time the term with the derivative of MAC wrt to the surface S_ref. The CM depends on
307+ # the total references area of all surfaces including the main wing and the MAC of them main wing itself
308+ # As result, this derivative has two parts only for the main wing.
309+ # partials["CM", name + "_S_ref"] = -np.outer(M_j, dMAC_dS * term)
310+ partials ["CM" , name + "_S_ref" ] = np .outer (M_j * fact , (1 / S_ref ))
311+
312+ # Cache the main wing's MAC derivatives
233313 base_name = name
234314 base_dMAC_dc = dMAC_dc
235315 base_dMAC_dw = dMAC_dw
236- base_dMAC_dS = dMAC_dS
237-
316+ # base_dMAC_dS = dMAC_dS
238317 else :
239318 # Apply this surface's portion of the moment to the MAC_wing term.
240- term = fact / (MAC_wing * MAC )
319+ # We need to do this because CM is normalized by the MAC of the main wing
320+ term = fact / MAC_wing
241321 partials ["CM" , base_name + "_chords" ] -= np .outer (M_j * term , base_dMAC_dc )
242322 partials ["CM" , base_name + "_widths" ] -= np .outer (M_j * term , base_dMAC_dw )
243- partials ["CM" , base_name + "_S_ref" ] -= np .outer (M_j , base_dMAC_dS * term )
323+ # partials["CM", base_name + "_S_ref"] -= np.outer(M_j, base_dMAC_dS * term)
324+ partials ["CM" , base_name + "_S_ref" ] += np .outer (M_j * fact , (1 / S_ref_wing ))
0 commit comments