Skip to content

Commit 2a5ffcf

Browse files
committed
integration test with new framat
1 parent 0b618b6 commit 2a5ffcf

File tree

2 files changed

+73
-128
lines changed

2 files changed

+73
-128
lines changed

ceasiompy/AeroFrame_new/aeroframe_run.py

+48-35
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from ceasiompy.PyAVL.pyavl import main as run_avl
2929
from ceasiompy.utils.ceasiompyutils import call_main
30+
from ceasiompy.PyAVL.func.utils import create_case_dir
3031
from ceasiompy.PyAVL.func.plot import convert_ps_to_pdf
3132
from ceasiompy.utils.ceasiompyutils import get_aeromap_conditions
3233
from cpacspy.cpacsfunctions import (
@@ -43,7 +44,7 @@
4344
plot_deformed_wing
4445
)
4546
from ceasiompy.AeroFrame_new.func.config import (
46-
read_AVL_fe_file,
47+
read_avl_fe_file,
4748
create_framat_model,
4849
get_material_properties,
4950
get_section_properties,
@@ -71,7 +72,12 @@
7172

7273

7374
# TODO: Reduce complexity
74-
def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
75+
def aeroelastic_loop(
76+
cpacs,
77+
results_dir,
78+
case_dir_path,
79+
q, xyz, fxyz
80+
):
7581
"""Function to execute the aeroelastic-loop.
7682
7783
Function 'aeroelastic_loop' executes the aeroelastic-loop,
@@ -90,12 +96,10 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
9096
res (list): residual of the mid-chord wing tip deflection.
9197
"""
9298

93-
cpacs = CPACS(cpacs_path)
94-
95-
AVL_ITER1_PATH = Path(CASE_PATH, "Iteration_1", "AVL")
99+
AVL_ITER1_PATH = Path(case_dir_path, "Iteration_1", "AVL")
96100

97101
# Get the path to the undeformed/initial AVL geometry
98-
for path in AVL_ITER1_PATH.glob('*.avl'):
102+
for path in results_dir.glob('*.avl'):
99103
AVL_UNDEFORMED_PATH = path
100104
AVL_UNDEFORMED_COMMAND = Path(AVL_ITER1_PATH, "avl_commands.txt")
101105

@@ -111,10 +115,10 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
111115
wg_center_z_list,
112116
wg_chord_list,
113117
wg_scaling
114-
) = compute_cross_section(cpacs_path)
118+
) = compute_cross_section(cpacs)
115119

116120
# Get the properties of the wing material and the number of beam nodes to use
117-
young_modulus, shear_modulus, material_density = get_material_properties(cpacs_path)
121+
young_modulus, shear_modulus, material_density = get_material_properties(cpacs)
118122
N_beam = get_value_or_default(cpacs.tixi, FRAMAT_MESH_XPATH + "/NumberNodes", 8)
119123

120124
# Define the coordinates of the wing root and tip
@@ -155,7 +159,7 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
155159
Zle_array[-1]])
156160

157161
# Get cross-section properties from CPACS file (if constants)
158-
area_const, Ix_const, Iy_const = get_section_properties(cpacs_path)
162+
area_const, Ix_const, Iy_const = get_section_properties(cpacs)
159163

160164
if area_const > 0:
161165
area_list = area_const * np.ones(len(wg_center_y_list))
@@ -189,10 +193,10 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
189193
log.info("")
190194
log.info(f"----- FramAT: Deformation {n_iter} -----")
191195

192-
Path(CASE_PATH, f"Iteration_{n_iter + 1}", "AVL").mkdir(parents=True, exist_ok=True)
193-
Path(CASE_PATH, f"Iteration_{n_iter}", "FramAT").mkdir(parents=True, exist_ok=True)
194-
AVL_ITER_PATH = Path(CASE_PATH, f"Iteration_{n_iter + 1}", "AVL")
195-
FRAMAT_ITER_PATH = Path(CASE_PATH, f"Iteration_{n_iter}", "FramAT")
196+
Path(case_dir_path, f"Iteration_{n_iter + 1}", "AVL").mkdir(parents=True, exist_ok=True)
197+
Path(case_dir_path, f"Iteration_{n_iter}", "FramAT").mkdir(parents=True, exist_ok=True)
198+
AVL_ITER_PATH = Path(case_dir_path, f"Iteration_{n_iter + 1}", "AVL")
199+
FRAMAT_ITER_PATH = Path(case_dir_path, f"Iteration_{n_iter}", "FramAT")
196200
AVL_DEFORMED_PATH = Path(AVL_ITER_PATH, "deformed.avl")
197201
AVL_DEFORMED_COMMAND = Path(AVL_ITER_PATH, "avl_commands.txt")
198202

@@ -217,7 +221,7 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
217221
Iy_profile,
218222
chord_profile,
219223
twist_profile,
220-
CASE_PATH,
224+
case_dir_path,
221225
AVL_UNDEFORMED_PATH,
222226
wg_scaling)
223227

@@ -283,7 +287,7 @@ def aeroelastic_loop(cpacs_path, CASE_PATH, q, xyz, fxyz):
283287

284288
# Read the new forces file to extract the loads
285289
FE_PATH = Path(AVL_ITER_PATH, "fe.txt")
286-
_, _, _, xyz_list, p_xyz_list, _ = read_AVL_fe_file(FE_PATH, plot=False)
290+
_, _, _, xyz_list, p_xyz_list, _ = read_avl_fe_file(FE_PATH, plot=False)
287291

288292
xyz = xyz_list[0]
289293
fxyz = np.array(p_xyz_list[0]) * q
@@ -368,7 +372,7 @@ def main(cpacs: CPACS, results_dir: Path) -> None:
368372

369373
# First AVL run
370374
# You need to first load the default values of AVL
371-
# Then you add back the ones that you wanted to specify...
375+
# Then you add back the ones that you wanted to specify.
372376
run_avl(cpacs, results_dir)
373377

374378
for i_case, _ in enumerate(alt_list):
@@ -380,38 +384,47 @@ def main(cpacs: CPACS, results_dir: Path) -> None:
380384
Atm = Atmosphere(alt)
381385
fluid_density = Atm.density[0]
382386
fluid_velocity = Atm.speed_of_sound[0] * mach
383-
q = 0.5 * fluid_density * fluid_velocity**2
384-
385-
case_dir_name = (
386-
f"Case{str(i_case).zfill(2)}_alt{alt}_mach{round(mach, 2)}"
387-
f"_aoa{round(aoa, 1)}_aos{round(aos, 1)}"
387+
rho = 0.5 * fluid_density * fluid_velocity**2
388+
389+
case_dir_path = create_case_dir(
390+
results_dir,
391+
i_case,
392+
alt,
393+
mach=mach,
394+
aoa=aoa,
395+
aos=aos,
396+
q=0.0,
397+
p=0.0,
398+
r=0.0,
388399
)
400+
Path(case_dir_path, "Iteration_1", "AVL").mkdir(parents=True, exist_ok=True)
389401

390-
CASE_PATH = Path(results_dir, case_dir_name)
391-
Path(CASE_PATH, "Iteration_1", "AVL").mkdir(parents=True, exist_ok=True)
392-
AVL_ITER_PATH = Path(CASE_PATH, "Iteration_1", "AVL")
402+
avl_iter_path = Path(case_dir_path, "Iteration_1", "AVL")
393403

394-
for file_path in CASE_PATH.iterdir():
404+
for file_path in case_dir_path.iterdir():
395405
if file_path.is_file():
396-
shutil.move(str(file_path), str(AVL_ITER_PATH / file_path.name))
406+
shutil.move(str(file_path), str(avl_iter_path / file_path.name))
397407

398-
FE_PATH = Path(AVL_ITER_PATH, "fe.txt")
399-
_, _, _, xyz_list, p_xyz_list, _ = read_AVL_fe_file(FE_PATH, plot=False)
408+
fe_path = Path(avl_iter_path, "fe.txt")
409+
_, _, _, xyz_list, p_xyz_list, _ = read_avl_fe_file(fe_path, plot=False)
400410

401-
f_xyz_array = np.array(p_xyz_list) * q
411+
f_xyz_array = np.array(p_xyz_list) * rho
402412

403413
# Start the aeroelastic loop
404-
tip_deflection, residuals = aeroelastic_loop(cpacs_path,
405-
CASE_PATH,
406-
q,
407-
xyz_list[0],
408-
f_xyz_array[0])
414+
tip_deflection, residuals = aeroelastic_loop(
415+
cpacs,
416+
results_dir,
417+
case_dir_path,
418+
rho,
419+
xyz_list[0],
420+
f_xyz_array[0],
421+
)
409422

410423
# Write results in CPACS out
411424
create_branch(tixi, FRAMAT_RESULTS_XPATH + "/TipDeflection")
412425
tixi.updateDoubleElement(FRAMAT_RESULTS_XPATH + "/TipDeflection", tip_deflection[-1], "%g")
413426

414-
plot_convergence(tip_deflection, residuals, wkdir=CASE_PATH)
427+
plot_convergence(tip_deflection, residuals, wkdir=case_dir_path)
415428

416429

417430
# =================================================================================================

ceasiompy/AeroFrame_new/func/config.py

+25-93
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
# ==============================================================================
1717

1818
import re
19-
import math
2019
import numpy as np
2120
import pandas as pd
2221
import matplotlib.pyplot as plt
@@ -25,6 +24,10 @@
2524
from cpacspy.cpacsfunctions import open_tixi
2625
from cpacspy.cpacsfunctions import get_value_or_default
2726
from ceasiompy.CPACS2SUMO.func.getprofile import get_profile_coord
27+
from ceasiompy.utils.geometryfunctions import (
28+
sum_points,
29+
get_positionings,
30+
)
2831
from ceasiompy.utils.mathsfunctions import (
2932
euler2fix,
3033
rotate_points,
@@ -39,8 +42,8 @@
3942
from scipy import interpolate
4043
from cpacspy.cpacspy import CPACS
4144
from ceasiompy.utils.generalclasses import (
45+
Point,
4246
Transformation,
43-
SimpleNamespace,
4447
)
4548

4649
from ceasiompy import log
@@ -173,7 +176,7 @@ def parse_AVL_surface(string):
173176
return surface_name, nspanwise, nchord_strip, xyz, p_xyz, slope_list
174177

175178

176-
def read_AVL_fe_file(FE_PATH, plot=False):
179+
def read_avl_fe_file(FE_PATH, plot=False):
177180
"""Function to read AVL 'fe.txt' element force file,
178181
and extract the aerodynamic loads calling the function
179182
'parse_AVL_surface'.
@@ -355,7 +358,7 @@ def create_framat_model(young_modulus, shear_modulus, material_density,
355358
return model
356359

357360

358-
def get_material_properties(cpacs_path):
361+
def get_material_properties(cpacs):
359362
"""Function to read the material properties for structural
360363
calculations.
361364
@@ -372,20 +375,19 @@ def get_material_properties(cpacs_path):
372375
material_density (float): Density of the material [kg/m^3].
373376
374377
"""
375-
cpacs = CPACS(cpacs_path)
376-
377-
young_modulus = get_value_or_default(cpacs.tixi,
378+
tixi = cpacs.tixi
379+
young_modulus = get_value_or_default(tixi,
378380
FRAMAT_MATERIAL_XPATH + "/YoungModulus", 70)
379381

380-
shear_modulus = get_value_or_default(cpacs.tixi,
382+
shear_modulus = get_value_or_default(tixi,
381383
FRAMAT_MATERIAL_XPATH + "/ShearModulus", 27)
382384

383-
material_density = get_value_or_default(cpacs.tixi, FRAMAT_MATERIAL_XPATH + "/Density", 1960)
385+
material_density = get_value_or_default(tixi, FRAMAT_MATERIAL_XPATH + "/Density", 1960)
384386

385387
return young_modulus, shear_modulus, material_density
386388

387389

388-
def get_section_properties(cpacs_path):
390+
def get_section_properties(cpacs):
389391
"""Function reads the cross-section properties for structural
390392
calculations.
391393
@@ -402,11 +404,11 @@ def get_section_properties(cpacs_path):
402404
Iy (float): second moment of area about the x-axis [m^4].
403405
404406
"""
405-
cpacs = CPACS(cpacs_path)
407+
tixi = cpacs.tixi
406408

407-
area = get_value_or_default(cpacs.tixi, FRAMAT_SECTION_XPATH + "/Area", -1)
408-
Ix = get_value_or_default(cpacs.tixi, FRAMAT_SECTION_XPATH + "/Ix", -1)
409-
Iy = get_value_or_default(cpacs.tixi, FRAMAT_SECTION_XPATH + "/Iy", -1)
409+
area = get_value_or_default(tixi, FRAMAT_SECTION_XPATH + "/Area", -1)
410+
Ix = get_value_or_default(tixi, FRAMAT_SECTION_XPATH + "/Ix", -1)
411+
Iy = get_value_or_default(tixi, FRAMAT_SECTION_XPATH + "/Iy", -1)
410412

411413
return area, Ix, Iy
412414

@@ -613,7 +615,7 @@ def compute_distance_and_moment(row):
613615

614616

615617
# TODO: Reduce complexity
616-
def compute_cross_section(cpacs_path):
618+
def compute_cross_section(cpacs):
617619
"""
618620
Function 'compute_cross_section' computes the area, the second moments of area,
619621
and additional geometric properties of each cross-section of the wing.
@@ -638,7 +640,7 @@ def compute_cross_section(cpacs_path):
638640
wg_chord_list (list): list of the chord length of each cross-section [m].
639641
640642
"""
641-
tixi = open_tixi(cpacs_path)
643+
tixi = cpacs.tixi
642644

643645
# Wing(s) ------------------------------------------------------------------
644646
if tixi.checkElement(WINGS_XPATH):
@@ -681,76 +683,7 @@ def compute_cross_section(cpacs_path):
681683
round(wing_transf.scaling.z, 3)]
682684

683685
# Positionings
684-
if tixi.checkElement(wing_xpath + "/positionings"):
685-
pos_cnt = tixi.getNamedChildrenCount(wing_xpath + "/positionings", "positioning")
686-
log.info(str(pos_cnt) + ' "positioning" has been found : ')
687-
688-
pos_x_list = []
689-
pos_y_list = []
690-
pos_z_list = []
691-
from_sec_list = []
692-
to_sec_list = []
693-
694-
for i_pos in range(pos_cnt):
695-
pos_xpath = wing_xpath + "/positionings/positioning[" + str(i_pos + 1) + "]"
696-
697-
length = tixi.getDoubleElement(pos_xpath + "/length")
698-
sweep_deg = tixi.getDoubleElement(pos_xpath + "/sweepAngle")
699-
sweep = math.radians(sweep_deg)
700-
dihedral_deg = tixi.getDoubleElement(pos_xpath + "/dihedralAngle")
701-
dihedral = math.radians(dihedral_deg)
702-
703-
# Get the corresponding translation of each positioning
704-
pos_x_list.append(length * math.sin(sweep))
705-
pos_y_list.append(length * math.cos(dihedral) * math.cos(sweep))
706-
pos_z_list.append(length * math.sin(dihedral) * math.cos(sweep))
707-
708-
# Get which section are connected by the positioning
709-
if tixi.checkElement(pos_xpath + "/fromSectionUID"):
710-
from_sec = tixi.getTextElement(pos_xpath + "/fromSectionUID")
711-
else:
712-
from_sec = ""
713-
from_sec_list.append(from_sec)
714-
715-
if tixi.checkElement(pos_xpath + "/toSectionUID"):
716-
to_sec = tixi.getTextElement(pos_xpath + "/toSectionUID")
717-
else:
718-
to_sec = ""
719-
to_sec_list.append(to_sec)
720-
721-
# Re-loop though the positioning to re-order them
722-
for j_pos in range(pos_cnt):
723-
if from_sec_list[j_pos] == "":
724-
prev_pos_x = 0
725-
prev_pos_y = 0
726-
prev_pos_z = 0
727-
elif from_sec_list[j_pos] == to_sec_list[j_pos - 1]:
728-
prev_pos_x = pos_x_list[j_pos - 1]
729-
prev_pos_y = pos_y_list[j_pos - 1]
730-
prev_pos_z = pos_z_list[j_pos - 1]
731-
else:
732-
index_prev = to_sec_list.index(from_sec_list[j_pos])
733-
prev_pos_x = pos_x_list[index_prev]
734-
prev_pos_y = pos_y_list[index_prev]
735-
prev_pos_z = pos_z_list[index_prev]
736-
737-
pos_x_list[j_pos] += prev_pos_x
738-
pos_y_list[j_pos] += prev_pos_y
739-
pos_z_list[j_pos] += prev_pos_z
740-
741-
else:
742-
log.warning('No "positionings" have been found!')
743-
pos_cnt = 0
744-
745-
# Sections
746-
sec_cnt = tixi.getNamedChildrenCount(wing_xpath + "/sections", "section")
747-
log.info(" -" + str(sec_cnt) + " wing sections have been found")
748-
749-
if pos_cnt == 0:
750-
pos_x_list = [0.0] * sec_cnt
751-
pos_y_list = [0.0] * sec_cnt
752-
pos_z_list = [0.0] * sec_cnt
753-
686+
sec_cnt, pos_x_list, pos_y_list, pos_z_list = get_positionings(tixi, wing_xpath, "wing")
754687
for i_sec in range(sec_cnt):
755688
sec_xpath = wing_xpath + "/sections/section[" + str(i_sec + 1) + "]"
756689
sec_uid = tixi.getTextAttribute(sec_xpath, "uID")
@@ -802,13 +735,12 @@ def compute_cross_section(cpacs_path):
802735

803736
# Add rotation from element and sections
804737
# Adding the two angles: Maybe not work in every case!!!
805-
add_rotation = SimpleNamespace()
806-
add_rotation.x = elem_transf.rotation.x + \
807-
sec_transf.rotation.x + wg_sk_transf.rotation.x
808-
add_rotation.y = elem_transf.rotation.y + \
809-
sec_transf.rotation.y + wg_sk_transf.rotation.y
810-
add_rotation.z = elem_transf.rotation.z + \
811-
sec_transf.rotation.z + wg_sk_transf.rotation.z
738+
x, y, z = sum_points(
739+
elem_transf.rotation,
740+
sec_transf.rotation,
741+
sec_transf.rotation
742+
)
743+
add_rotation = Point(x, y, z)
812744

813745
# Get Section rotation
814746
wg_sec_rot = euler2fix(add_rotation)

0 commit comments

Comments
 (0)