Aeroacoustics

Contents

Aeroacoustics#

This script demonstrates the setup for obtaining aeroacoustic results for a quadcopter configuration using the Flow360 Python API. It outlines the process of defining rotating zones, configuring an unsteady simulation vital for capturing time-varying flow features, and setting up aeroacoustic outputs based on the Ffowcs-Williams and Hawkings (FWH) analogy. The example focuses on specifying acoustic observer locations and retrieving the resulting acoustic data.

  1import pandas as pd
  2
  3import flow360 as fl
  4from flow360.examples import Quadcopter
  5
  6Quadcopter.get_files()
  7
  8project = fl.Project.from_volume_mesh(
  9    Quadcopter.mesh_filename, name="Aeroacoustic results from Python"
 10)
 11
 12vm = project.volume_mesh
 13
 14with fl.SI_unit_system:
 15    rotation_zone_1 = vm["zone_r1"]
 16    rotation_zone_1.center = [-0.125, 0.125, 0.0055]
 17    rotation_zone_1.axis = [0, 0, 1]
 18
 19    rotation_zone_2 = vm["zone_r2"]
 20    rotation_zone_2.center = [-0.125, -0.125, 0.0055]
 21    rotation_zone_2.axis = [0, 0, -1]
 22
 23    rotation_zone_3 = vm["zone_r3"]
 24    rotation_zone_3.center = [0.125, -0.125, 0.0055]
 25    rotation_zone_3.axis = [0, 0, 1]
 26
 27    rotation_zone_4 = vm["zone_r4"]
 28    rotation_zone_4.center = [0.125, 0.125, 0.0055]
 29    rotation_zone_4.axis = [0, 0, -1]
 30
 31    omega = 6000 * fl.u.rpm
 32
 33    # Time step size will be calculated based on predetermined degrees per time step (3 deg for this run)
 34    deg_per_time_step_0 = 3.0 * fl.u.deg
 35    time_step_0 = deg_per_time_step_0 / omega.to("deg/s")
 36
 37    # Amount of time steps will be adjusted to satisfy the required amount of revolutions (5 rev for this run)
 38    revolution_time_0 = 360 * fl.u.deg / omega.to("deg/s")
 39    steps_0 = int(5 * revolution_time_0 / time_step_0)
 40
 41    params = fl.SimulationParams(
 42        reference_geometry=fl.ReferenceGeometry(
 43            area=0.0447726728530549,
 44            moment_center=[0, 0, 0],
 45            moment_length=[0.11938, 0.11938, 0.11938],
 46        ),
 47        operating_condition=fl.AerospaceCondition.from_mach(
 48            mach=0,
 49            thermal_state=fl.ThermalState(temperature=293.15),
 50            reference_mach=0.21868415800906676,
 51        ),
 52        time_stepping=fl.Unsteady(
 53            step_size=time_step_0,
 54            steps=steps_0,
 55        ),
 56        models=[
 57            fl.Fluid(
 58                navier_stokes_solver=fl.NavierStokesSolver(
 59                    absolute_tolerance=1e-10,
 60                    relative_tolerance=0.1,
 61                    order_of_accuracy=1,
 62                    linear_solver=fl.LinearSolver(max_iterations=30),
 63                ),
 64                turbulence_model_solver=fl.SpalartAllmaras(
 65                    absolute_tolerance=1e-8,
 66                    relative_tolerance=0.1,
 67                    order_of_accuracy=1,
 68                    linear_solver=fl.LinearSolver(max_iterations=20),
 69                ),
 70            ),
 71            fl.Wall(
 72                surfaces=[
 73                    vm["zone_s/airframe"],
 74                    vm["zone_r1/blade1"],
 75                    vm["zone_r2/blade2"],
 76                    vm["zone_r3/blade3"],
 77                    vm["zone_r4/blade4"],
 78                ],
 79            ),
 80            fl.Freestream(surfaces=vm["zone_s/farfield"]),
 81            fl.Rotation(
 82                name="Rotation",
 83                volumes=[rotation_zone_1, rotation_zone_2, rotation_zone_3, rotation_zone_4],
 84                spec=fl.AngularVelocity(value=omega),
 85            ),
 86        ],
 87    )
 88
 89case = project.run_case(params, "First order run")
 90
 91
 92case.params.models[0].navier_stokes_solver.order_of_accuracy = 2
 93case.params.models[0].navier_stokes_solver.linear_solver = fl.LinearSolver(max_iterations=25)
 94
 95case.params.models[0].turbulence_model_solver.order_of_accuracy = 2
 96case.params.models[0].turbulence_model_solver.linear_solver = fl.LinearSolver(max_iterations=25)
 97
 98deg_per_time_step_1 = 0.404496 * fl.u.deg
 99time_step_1 = deg_per_time_step_1 / omega.to("deg/s")
100
101revolution_time_1 = 360 * fl.u.deg / omega.to("deg/s")
102steps_1 = int(5 * revolution_time_1 / time_step_1)
103
104case.params.time_stepping.step_size = time_step_1
105case.params.time_stepping.steps = steps_1
106
107case_fork_1 = project.run_case(case.params, "Second order run", fork_from=case)
108
109case_fork_1.params.outputs = [
110    fl.AeroAcousticOutput(
111        observers=[
112            fl.Observer(position=[0, -1.905, 0] * fl.u.m, group_name="1"),
113            fl.Observer(position=[0, -1.7599905, -0.72901194] * fl.u.m, group_name="1"),
114            fl.Observer(position=[0, -1.3470384, -1.3470384] * fl.u.m, group_name="1"),
115            fl.Observer(position=[0.9525, -0.9525, -1.3470384] * fl.u.m, group_name="1"),
116            fl.Observer(position=[1.3470384, 0, -1.3470384] * fl.u.m, group_name="1"),
117            fl.Observer(position=[0, 0, 1.905] * fl.u.m, group_name="1"),
118            fl.Observer(position=[0, -0.37164706, 1.8683959] * fl.u.m, group_name="1"),
119            fl.Observer(position=[0, -1.868396, 0.37164707] * fl.u.m, group_name="1"),
120            fl.Observer(position=[1.295, 0, -0.767] * fl.u.m, group_name="2"),
121        ],
122        write_per_surface_output=True,
123    )
124]
125
126case_fork_2 = project.run_case(case_fork_1.params, "Final run", fork_from=case_fork_1)
127
128case_fork_2.wait()
129
130results = case_fork_2.results
131
132total_acoustics = results.aeroacoustics
133print(total_acoustics)
134
135# There are also surface specific aeroacoustic output files
136blade_1_acoustics = results.download_file_by_name(
137    "results/surface_zone_r1_blade1_acoustics_v3.csv", to_folder="aeroacoustic_results"
138)
139blade_1_acoustics = pd.read_csv(blade_1_acoustics)
140print(blade_1_acoustics)
141blade_2_acoustics = results.download_file_by_name(
142    "results/surface_zone_r2_blade2_acoustics_v3.csv", to_folder="aeroacoustic_results"
143)
144blade_2_acoustics = pd.read_csv(blade_2_acoustics)
145print(blade_2_acoustics)
146blade_3_acoustics = results.download_file_by_name(
147    "results/surface_zone_r3_blade3_acoustics_v3.csv", to_folder="aeroacoustic_results"
148)
149blade_3_acoustics = pd.read_csv(blade_3_acoustics)
150print(blade_3_acoustics)
151blade_4_acoustics = results.download_file_by_name(
152    "results/surface_zone_r4_blade4_acoustics_v3.csv", to_folder="aeroacoustic_results"
153)
154blade_4_acoustics = pd.read_csv(blade_4_acoustics)
155print(blade_4_acoustics)

Notes#

  • The script showcases the configuration of aeroacoustic data computation using fl.AeroAcousticOutput and the definition of microphone locations via fl.Observer.

  • It illustrates how to retrieve both the total acoustic results aggregated over all sources and the acoustic contributions from individual surfaces after the simulation concludes.

  • A simulation forking strategy (using the fork_from argument in project.run_case) is employed to initialize the flow field before adding the specific acoustic output requests for the final simulation phase.