Source code for pyLOM.NN.aerodynamics

#!/usr/bin/env python
#
# pyLOM - Python Low Order Modeling.
#
# Global aerodynamic calculation routines.
#
# Last rev: 22/05/2025

import torch

from ..utils.errors     import raiseError

[docs] def global_coeff( CoefPressure: torch.Tensor, SRef: float, MomentCenter: torch.Tensor, cRef: float, CoefSkinFriction: torch.Tensor = None, alpha: torch.Tensor = 0, coordinates: torch.Tensor = None, normals: torch.Tensor = None, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: r""" Calculate lift, drag and moment coefficients from pressure coefficient and skin friction coefficient. Args: CoefPressure (torch.Tensor): Tensor of shape (n,) or (n,1) with the pressure coefficients of the surface. SRef (float): Reference area. MomentCenter (torch.Tensor): Tensor of shape (3,) with the moment center coordinates. cRef (float): Reference chord length. CoefSkinFriction (torch.Tensor, optional): Tensor of shape (n,3) with the skin friction coefficients of the surface (default: `None). alpha (torch.Tensor): Angle of attack in deg. coordinates (torch.Tensor): Tensor of shape (n,3) with the coordinates of the surface points. normals (torch.Tensor): Tensor of shape (n,3) with the normal vectors of the surface. Returns: tuple[torch.Tensor, torch.Tensor, torch.Tensor]: Coefficients of lift (CL), drag (CD) and moment (CM) respectively. """ if normals.ndimension() == 1 or normals.shape[1] == 1: normals = normals.view(-1, 3) if normals.shape[1] != 3: raiseError(f"Normals must have shape (n,3).") if coordinates.ndimension() == 1 or coordinates.shape[1] == 1: coordinates = coordinates.view(-1, 3) if coordinates.shape[1] != 3: raiseError(f"Coordinates must have shape (n,3).") alpha = alpha*torch.pi/180 r = coordinates - MomentCenter.view(1, 3) # Pressure forces ForcePressure = torch.zeros_like(coordinates) CoefLiftPressure, CoefDragPressure, CoefMomentPressure = 0, 0, 0 if CoefPressure is not None: if CoefPressure.ndimension() == 1 or CoefPressure.shape[1] == 1: ForcePressure = -CoefPressure.view(-1, 1) * normals CoefLiftPressure = torch.sum(ForcePressure[:, 2]*torch.cos(alpha) - ForcePressure[:, 0]*torch.sin(alpha)) CoefDragPressure = torch.sum(ForcePressure[:, 2]*torch.sin(alpha) + ForcePressure[:, 0]*torch.cos(alpha)) CoefMomentPressure = torch.sum(torch.linalg.cross(r, ForcePressure)[:,1]) else: raiseError(f"CoefPressure must have shape (n,) or (n,1).") # Skin friction forces ForceFriction = torch.zeros_like(coordinates) CoefLiftFriction, CoefDragFriction, CoefMomentFriction = 0, 0, 0 if CoefSkinFriction is not None: if CoefSkinFriction.ndimension() == 1: CoefSkinFriction = CoefSkinFriction.view(-1, 3) elif CoefSkinFriction.shape[1] != 3: raiseError(f"CoefSkinFriction must have shape (n,3).") Si = torch.norm(normals, dim=1).view(-1, 1) ForceFriction = CoefSkinFriction * Si CoefLiftFriction = torch.sum(ForceFriction[:, 2]*torch.cos(alpha)) - torch.sum(ForceFriction[:, 0]*torch.sin(alpha)) CoefDragFriction = torch.sum(ForceFriction[:, 2]*torch.sin(alpha)) + torch.sum(ForceFriction[:, 0]*torch.cos(alpha)) CoefMomentFriction = torch.sum(torch.linalg.cross(r, ForceFriction)[:,1]) if CoefPressure is None and CoefSkinFriction is None: raiseError(f"At least one of CoefPressure or CoefSkinFriction must be provided.") # Coefficients CM = (CoefMomentPressure + CoefMomentFriction) / (SRef * cRef) CL = (CoefLiftPressure + CoefLiftFriction) / SRef CD = (CoefDragPressure + CoefDragFriction) / SRef return CL, CD, CM