Unsteady Solver Convergence Testing with Variable GeometryΒΆ

"""This script is an example of analyzing the unsteady convergence of an
UnsteadyProblem with custom geometry and non static motion. It should take 10-20
minutes to run. It will display the convergence progress and results in the console."""

import pterasoftware as ps

# Configure logging to display info level messages. This is important for seeing the
# output from the convergence function.
ps.set_up_logging(level="Info")

# Create an Airplane and AirplaneMovement
example_airplane = ps.geometry.airplane.Airplane(
    wings=[
        ps.geometry.wing.Wing(
            wing_cross_sections=[
                ps.geometry.wing_cross_section.WingCrossSection(
                    airfoil=ps.geometry.airfoil.Airfoil(
                        name="naca2412",
                    ),
                    num_spanwise_panels=8,
                    chord=1.0,
                    Lp_Wcsp_Lpp=(0.0, 0.0, 0.0),
                    control_surface_symmetry_type="asymmetric",
                    spanwise_spacing="uniform",
                ),
                ps.geometry.wing_cross_section.WingCrossSection(
                    airfoil=ps.geometry.airfoil.Airfoil(
                        name="naca2412",
                    ),
                    num_spanwise_panels=None,
                    chord=1.0,
                    Lp_Wcsp_Lpp=(0.0, 3.0, 0.0),
                    control_surface_symmetry_type="asymmetric",
                    spanwise_spacing=None,
                ),
            ],
            name="Main Wing",
            Ler_Gs_Cgs=(0.0, 0.5, 0.0),
            symmetric=True,
            symmetryNormal_G=(0.0, 1.0, 0.0),
            symmetryPoint_G_Cg=(0.0, 0.0, 0.0),
            chordwise_spacing="uniform",
        ),
    ],
    name="Example Airplane",
)
example_airplane_movement = ps.movements.airplane_movement.AirplaneMovement(
    base_airplane=example_airplane,
    wing_movements=[
        ps.movements.wing_movement.WingMovement(
            base_wing=example_airplane.wings[0],
            wing_cross_section_movements=[
                ps.movements.wing_cross_section_movement.WingCrossSectionMovement(
                    base_wing_cross_section=example_airplane.wings[
                        0
                    ].wing_cross_sections[0]
                ),
                ps.movements.wing_cross_section_movement.WingCrossSectionMovement(
                    base_wing_cross_section=example_airplane.wings[
                        0
                    ].wing_cross_sections[1]
                ),
            ],
            ampAngles_Gs_to_Wn_ixyz=(15.0, 0.0, 0.0),
            periodAngles_Gs_to_Wn_ixyz=(1.0, 0.0, 0.0),
            spacingAngles_Gs_to_Wn_ixyz=("sine", "sine", "sine"),
            phaseAngles_Gs_to_Wn_ixyz=(0.0, 0.0, 0.0),
        ),
        ps.movements.wing_movement.WingMovement(
            base_wing=example_airplane.wings[1],
            wing_cross_section_movements=[
                ps.movements.wing_cross_section_movement.WingCrossSectionMovement(
                    base_wing_cross_section=example_airplane.wings[
                        1
                    ].wing_cross_sections[0]
                ),
                ps.movements.wing_cross_section_movement.WingCrossSectionMovement(
                    base_wing_cross_section=example_airplane.wings[
                        1
                    ].wing_cross_sections[1]
                ),
            ],
            ampAngles_Gs_to_Wn_ixyz=(15.0, 0.0, 0.0),
            periodAngles_Gs_to_Wn_ixyz=(1.0, 0.0, 0.0),
            spacingAngles_Gs_to_Wn_ixyz=("sine", "sine", "sine"),
            phaseAngles_Gs_to_Wn_ixyz=(0.0, 0.0, 0.0),
        ),
    ],
)

# Create an OperatingPoint and an OperatingPointMovement.
example_operating_point = ps.operating_point.OperatingPoint()
example_operating_point_movement = (
    ps.movements.operating_point_movement.OperatingPointMovement(
        base_operating_point=example_operating_point
    )
)

# Create a Movement using the AirplaneMovement and OperatingPointMovement
# objects.
example_movement = ps.movements.movement.Movement(
    airplane_movements=[example_airplane_movement],
    operating_point_movement=example_operating_point_movement,
    num_cycles=1,
)

del example_airplane_movement
del example_operating_point_movement

# Create an UnsteadyProblem. We will pass this into the convergence function.
example_problem = ps.problems.UnsteadyProblem(
    movement=example_movement, only_final_results=True
)

del example_movement

# Run the unsteady convergence analysis. This will run several simulations, modifying
# the wake state, wake length, average Panel aspect ratio, and number of chordwise
# Panels with each iteration. Once it detects that the net load coefficients haven't
# change by more than the convergence criteria (measured as an absolute percent
# error), it will return the parameters it found to result in a converged solution.
# See the analyze_unsteady_convergence function docstring for more details. The
# progress and results are displayed to the console.
ps.convergence.analyze_unsteady_convergence(
    ref_problem=example_problem,
    prescribed_wake=True,
    free_wake=True,
    num_cycles_bounds=(1, 4),
    panel_aspect_ratio_bounds=(4, 1),
    num_chordwise_panels_bounds=(3, 5),
    convergence_criteria=1.0,
    show_solver_progress=True,
)

# Check the console that the convergence analysis found that the solution converged
# with the following parameters:
# Wake type: free
# Wake length: 2 cycles
# Panel aspect ratio: 1
# Chordwise Panels: 3