Skip to content

Utils

Common functions used in multiple places

root()

Determines the root path of the application.

If the application is running in a frozen state (e.g., packaged by PyInstaller), it returns the path to the '_internal' directory within the executable's directory. Otherwise, it returns the path to the fourth parent directory of the current file.

Returns:

Name Type Description
Path Path

The root path of the application.

Source code in src/pymace/utils/file_path.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def root() -> Path:
    """
    Determines the root path of the application.

    If the application is running in a frozen state (e.g., packaged by PyInstaller),
    it returns the path to the '_internal' directory within the executable's directory.
    Otherwise, it returns the path to the fourth parent directory of the current file.

    Returns:
        Path: The root path of the application.
    """
    if getattr(sys, "frozen", False):
        application_path = Path(Path(sys.executable).resolve().parent, "_internal")
    elif __file__:
        application_path = Path(__file__).resolve().parents[3]
    return application_path

get_profil(airfoil)

Returns the profile with the given name.uv

Parameters:

Name Type Description Default
airfoil str

Namme of the file of the profile.

required

Returns:

Type Description
ndarray

np.ndarray: Array of the profile coordinates.

Source code in src/pymace/utils/mesh.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
def get_profil(airfoil: str) -> np.ndarray:
    """Returns the profile with the given name.uv

    Args:
        airfoil (str): Namme of the file of the profile.

    Returns:
        np.ndarray: Array of the profile coordinates.
    """
    file_location = Path(f"{root()}/data/airfoils/{airfoil}.dat")
    with open(file_location, "rt") as f:
        data = re.findall(r"([01]\.\d+) +([0\-]{1,2}\.\d+)", f.read())
    profil = [list(map(float, point)) for point in data]
    return np.asarray(profil)

get_profil_thickness(airfoil) cached

Calculate the maximum thickness of an airfoil profile.

This function retrieves the airfoil profile data and computes the maximum thickness by finding the maximum difference between the upper and lower surfaces of the airfoil.

Parameters:

Name Type Description Default
airfoil str

The name or identifier of the airfoil.

required

Returns:

Name Type Description
float float

The maximum thickness of the airfoil profile.

Source code in src/pymace/utils/mesh.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@cache
def get_profil_thickness(airfoil: str) -> float:
    """
    Calculate the maximum thickness of an airfoil profile.

    This function retrieves the airfoil profile data and computes the maximum
    thickness by finding the maximum difference between the upper and lower
    surfaces of the airfoil.

    Args:
        airfoil (str): The name or identifier of the airfoil.

    Returns:
        float: The maximum thickness of the airfoil profile.
    """
    profil = get_profil(airfoil)
    return max(profil[i][1] - profil[-i][1] for i in range(len(profil) // 2))

mesh(profil_innen, profil_außen)

Calculate the area, volume, and centroid of a mesh defined by inner and outer airfoils.

Parameters:

Name Type Description Default
profil_innen list or ndarray

The inner profile points of the mesh.

required
profil_außen list or ndarray

The outer profile points of the mesh.

required

Returns:

Name Type Description
tuple

A tuple containing: - area (float): The total area of the mesh. - volume (float): The total volume of the mesh. - p (np.ndarray): The centroid of the mesh as a 3D point.

Source code in src/pymace/utils/mesh.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
def mesh(profil_innen, profil_außen):
    """
    Calculate the area, volume, and centroid of a mesh defined by inner and outer airfoils.

    Args:
        profil_innen (list or np.ndarray): The inner profile points of the mesh.
        profil_außen (list or np.ndarray): The outer profile points of the mesh.

    Returns:
        tuple: A tuple containing:
            - area (float): The total area of the mesh.
            - volume (float): The total volume of the mesh.
            - p (np.ndarray): The centroid of the mesh as a 3D point.
    """
    area = 0
    volume = 0
    assert len(profil_innen) == len(profil_außen)
    indices = np.arange(len(profil_innen) // 2)
    io1s, io2s = profil_innen[indices], profil_innen[indices + 1]
    iu1s, iu2s = profil_innen[-indices], profil_innen[-indices - 1]
    ao1s, ao2s = profil_außen[indices], profil_außen[indices + 1]
    au1s, au2s = profil_außen[-indices], profil_außen[-indices - 1]

    volume += tri_volume(io1s, io2s, ao2s)
    volume += tri_volume(io1s, ao2s, ao1s)
    volume += tri_volume(iu1s, au2s, iu2s)
    volume += tri_volume(iu1s, au1s, au2s)
    volume += tri_volume(io1s, iu1s, iu2s)
    volume += tri_volume(io1s, iu2s, io2s)
    volume += tri_volume(ao1s, au2s, au1s)
    volume += tri_volume(ao1s, ao2s, au2s)

    area += tri_area(io1s, io2s, ao2s)
    area += tri_area(io1s, ao2s, ao1s)
    area += tri_area(iu1s, iu2s, au2s)
    area += tri_area(iu1s, au2s, au1s)

    p = np.array([0.0, 0.0, 0.0])
    p += tri_point(io1s, io2s, ao2s)
    p += tri_point(io1s, ao2s, ao1s)
    p += tri_point(iu1s, iu2s, au2s)
    p += tri_point(iu1s, au2s, au1s)
    p /= area

    return area, volume, p

scale(factors, vecs)

Scales the given vectors by the specified factors.

Parameters: factors (array-like): A 1D array of scaling factors. vecs (array-like): A 1D or 2D array of vectors to be scaled.

Returns: numpy.ndarray: A 2D array where each vector from vecs is scaled by the corresponding factor from factors.

Source code in src/pymace/utils/mesh.py
56
57
58
59
60
61
62
63
64
65
66
67
def scale(factors, vecs):
    """
    Scales the given vectors by the specified factors.

    Parameters:
    factors (array-like): A 1D array of scaling factors.
    vecs (array-like): A 1D or 2D array of vectors to be scaled.

    Returns:
    numpy.ndarray: A 2D array where each vector from `vecs` is scaled by the corresponding factor from `factors`.
    """
    return (factors * np.repeat(vecs[np.newaxis], len(factors), axis=0).T).T

tri_area(first, second, third)

Calculates the signed area created by three vectors

Parameters:

Name Type Description Default
first ndarray

Vector

required
second ndarray

Vector

required
third ndarray

Vector

required

Returns:

Name Type Description
float float

Area

Source code in src/pymace/utils/mesh.py
10
11
12
13
14
15
16
17
18
19
20
21
def tri_area(first: np.ndarray, second: np.ndarray, third: np.ndarray) -> float:
    """ Calculates the signed area created by three vectors

    Args:
        first (np.ndarray): Vector
        second (np.ndarray): Vector
        third (np.ndarray): Vector

    Returns:
        float: Area
    """
    return np.sum(np.linalg.norm(np.cross(second - first, third - first), axis=1)) / 2

tri_point(first, second, third)

Calculate the centroid of a triangle in 3D space.

Parameters: first (np.ndarray): A 1D array representing the coordinates of the first vertex of the triangle. second (np.ndarray): A 1D array representing the coordinates of the second vertex of the triangle. third (np.ndarray): A 1D array representing the coordinates of the third vertex of the triangle.

Returns: np.ndarray: A 1D array representing the coordinates of the centroid of the triangle.

Source code in src/pymace/utils/mesh.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def tri_point(first: np.ndarray, second: np.ndarray, third: np.ndarray) -> np.ndarray:
    """
    Calculate the centroid of a triangle in 3D space.

    Parameters:
    first (np.ndarray): A 1D array representing the coordinates of the first vertex of the triangle.
    second (np.ndarray): A 1D array representing the coordinates of the second vertex of the triangle.
    third (np.ndarray): A 1D array representing the coordinates of the third vertex of the triangle.

    Returns:
    np.ndarray: A 1D array representing the coordinates of the centroid of the triangle.
    """
    return (
        np.linalg.norm(np.cross(second - first, third - first), axis=1)
        @ (first + second + third)
    ) / 6

tri_volume(first, second, third)

Calculates the signed volume of the span of three vectors.

Parameters:

Name Type Description Default
first ndarray

Vector

required
second ndarray

Vector

required
third ndarray

Vector

required

Returns:

Name Type Description
float float

Volume

Source code in src/pymace/utils/mesh.py
24
25
26
27
28
29
30
31
32
33
34
35
def tri_volume(first: np.ndarray, second: np.ndarray, third: np.ndarray) -> float:
    """ Calculates the signed volume of the span of three vectors.

    Args:
        first (np.ndarray): Vector
        second (np.ndarray): Vector
        third (np.ndarray): Vector

    Returns:
        float: Volume
    """
    return np.sum(np.cross(first, second) * third) / 6

get_pid()

Returns the process ID (PID) of the current process if it is not the main process.

If the current process is the main process, an empty string is returned. Otherwise, the PID of the current process is returned as a string prefixed with an underscore.

Returns:

Name Type Description
str

An empty string if the current process is the main process, otherwise the PID of the current process prefixed with an underscore.

Source code in src/pymace/utils/mp.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def get_pid():
    """
    Returns the process ID (PID) of the current process if it is not the main process.

    If the current process is the main process, an empty string is returned.
    Otherwise, the PID of the current process is returned as a string prefixed with an underscore.

    Returns:
        str: An empty string if the current process is the main process, otherwise the PID of the current process prefixed with an underscore.
    """
    if current_process().name == "MainProcess":
        return ""
    else:
        return "_" + str(current_process().pid)

moment_at_position(mass, position, half_wing_span)

Calculates the moment at a specified position along a wing span, factoring in gravitational force and safety considerations.

Parameters:

Name Type Description Default
mass float

The mass at the given position.

required
position float

The position along the wing; its absolute value is used.

required
half_wing_span float

Half of the total wing span.

required

Returns:

Name Type Description
float

The computed moment, which is the product of the adjusted arm length, mass, gravitational constant (Constants.g), and a safety factor. The moment is increased by 50% if the position is within 10% of the half wing span, and then multiplied by an additional safety factor of 2.

Notes
  • The gravitational constant, Constants.g, is expected to be defined elsewhere in the code.
  • The absolute value of the position is used to ensure correct moment calculation regardless of direction.
Source code in src/pymace/utils/weight.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def moment_at_position(mass: float, position: float, half_wing_span: float):
    """
    Calculates the moment at a specified position along a wing span, factoring in gravitational force and safety considerations.

    Parameters:
        mass (float): The mass at the given position.
        position (float): The position along the wing; its absolute value is used.
        half_wing_span (float): Half of the total wing span.

    Returns:
        float: The computed moment, which is the product of the adjusted arm length, mass, gravitational constant (Constants.g), and a safety factor. The moment is increased by 50% if the position is within 10% of the half wing span, and then multiplied by an additional safety factor of 2.

    Notes:
        - The gravitational constant, Constants.g, is expected to be defined elsewhere in the code.
        - The absolute value of the position is used to ensure correct moment calculation regardless of direction.
    """
    position = abs(position)
    moment = (half_wing_span - position) * mass * Constants.g
    if position < 0.1 * half_wing_span:
        moment *= 1.5
    sicherheitsfaktor = 2
    return moment * sicherheitsfaktor