pterasoftware.convergence¶
Contains functions for analyzing the convergence of SteadyProblems and UnsteadyProblems.
Functions¶
Finds the converged parameters of a SteadyProblem solved using a given steady solver. |
|
Finds the converged parameters of an UnsteadyProblem solved using the UnsteadyRingVortexLatticeMethodSolver. |
Module Contents¶
- pterasoftware.convergence.analyze_steady_convergence(
- ref_problem: pterasoftware.problems.SteadyProblem,
- solver_type: str,
- panel_aspect_ratio_bounds: tuple[int, int] = (4, 1),
- num_chordwise_panels_bounds: tuple[int, int] = (3, 12),
- rtol: float | int = 0.05,
- atol: float | int = 0.001,
- coefficient_mask: tuple[bool, bool, bool, bool, bool, bool] | None = None,
- resolve_converged_solver: bool | numpy.bool_ = False,
- cache_path: str | pathlib.Path | None = None,
Finds the converged parameters of a SteadyProblem solved using a given steady solver.
Procedure:
Convergence is found by varying the SteadyProblem’s Airplanes’ Panels’ aspect ratios their Wings’ numbers of chordwise Panels. These values are iterated over via two nested for loops (with the number of chordwise Panels as the inner loop).
With each new combination of these values, the SteadyProblem is solved, and each Airplane’s six load coefficients are stored: the three force coefficients (in wind axes) and the three moment coefficients (in wind axes, relative to the first Airplane’s CG), or (cFX_W, cFY_W, cFZ_W, cMX_W_CgP1, cMY_W_CgP1, cMZ_W_CgP1). Then, convergence is checked per coefficient between this iteration and the iterations with incrementally coarser meshes in the two parameter directions (Panel aspect ratio and number of chordwise Panels). A coefficient is converged in a parameter direction when its absolute change from the coarser iteration is at most atol + rtol * max(abs(this), abs(coarser)). A parameter direction is converged when every unmasked coefficient of every Airplane is converged in that direction, so a multi- Airplane study converges only once all its Airplanes have.
If an iteration is converged in both parameter directions, then we exit the nested for loops and return the converged parameters. However, the converged parameters are actually the values incrementally coarser than the final values, because refining from the coarser values to the final ones changed every unmasked coefficient by within the tolerance.
Notes:
There are two edge cases to this function. The first is if the user inputs equal values for the coarsest and finest values of either the Panel aspect ratio or the number of chordwise Panels (e.g. panel_aspect_ratio_bounds=(2, 2)). Then, this parameter will not be iterated over, and convergence will only be checked for the other parameter.
The second edge case happens if the Panel aspect ratio has not converged at a value of 1. This is the gold standard value for Panel aspect ratio, so this function will return 1 for the converged value of Panel aspect ratio. In the code below, this state is referred to as a “saturated” Panel aspect ratio case.
Each Wing is refined according to how its spanwise mesh was defined. A non-edge- defined Wing (one built from WingCrossSections) is refined by sweeping its number of spanwise Panels to hit the target Panel aspect ratio, holding its WingCrossSections fixed. An edge-defined Wing (one built from edge curves with Wing.from_edge_points) is refined by resampling its stored edge curves into the number of WingCrossSections that hits the target Panel aspect ratio, preserving its planform shape. An Airplane may hold both kinds of Wing at once. A Wing that has been exploded into single-panel strips cannot be refined and is rejected.
- Parameters:
ref_problem – The SteadyProblem whose converged parameters will be found.
solver_type – Determines what type of steady solver will be used to analyze the SteadyProblem. The options are “steady horseshoe vortex lattice method” and “steady ring vortex lattice method”.
panel_aspect_ratio_bounds – A tuple of two ints, in descending order, that determines the range of Panel aspect ratios to consider, from largest to smallest. This value dictates the Panels’ average y component length (in wing cross section parent axes) divided their average x component width (in wing cross section parent axes). Historically, these values range between 5 and 1. Values above 5 can be used for a coarser mesh, but the minimum value cannot be less than 1. The default is (4, 1).
num_chordwise_panels_bounds – A tuple of two ints, in ascending order, that determines the range of values to use for the Wings’ numbers of chordwise panels. The default is (3, 12).
rtol – A positive number (int or float) giving the relative tolerance for the per-coefficient convergence check. A coefficient is converged in a parameter direction when its absolute change from the incrementally coarser iteration is at most atol + rtol * max(abs(this), abs(coarser)). Set this smaller for a stricter convergence. Values are converted to floats internally. The default is 0.05.
atol – A positive number (int or float) giving the absolute tolerance floor for the per-coefficient convergence check. It keeps coefficients that sit near zero from being held to an unreachable relative tolerance. Values are converted to floats internally. The default is 0.001.
coefficient_mask – A tuple of six bools that determines which of the six load coefficients (cFX_W, cFY_W, cFZ_W, cMX_W_CgP1, cMY_W_CgP1, cMZ_W_CgP1, in that order) must converge, or None to require all six. At least one element must be True. Use this to ignore coefficients that are physically irrelevant to the analysis. The default is None.
resolve_converged_solver – A bool for whether to recreate and run the solver at the converged parameters and return it. Because finding convergence is expensive, this defaults to False, in which case the returned solver is None. When True, the solver is rebuilt at the converged parameters (which are frequently coarser than the last iteration run) and run with streamlines calculated, so the returned solver is ready to use. The default is False.
cache_path – An optional path (a str or Path, which must end with “.json”) to a JSON file that caches each iteration’s solved load coefficients and solve time, keyed on the reference problem and the mesh parameters, together with the mesh counts it resolved (the spanwise Panel and WingCrossSection counts). When given, an iteration already in the cache reuses those stored coefficients and counts instead of re-running the solver and re-resolving the mesh, and each new iteration is written through to the file, so an interrupted or repeated study reuses the work it has already done. A cached iteration reports its stored solve time, so a warm run’s convergence report still shows how long the converged mesh took to solve. An iteration whose coefficients and counts are all cached also skips building its meshed problem. The mesh counts are keyed on the absolute mesh rather than a sweep index, so a later run over different bounds still reuses any iteration it shares. When None, no cache is read or written. The default is None.
- Returns:
A tuple of two ints and a solver, or a tuple of three Nones. In order, the first two elements are the converged Panel aspect ratio and the converged number of chordwise Panels. The third element is the converged solver if resolve_converged_solver is True, otherwise None. If the function could not find a set of converged parameters, it returns (None, None, None).
- pterasoftware.convergence.analyze_unsteady_convergence(
- ref_problem: pterasoftware.problems.UnsteadyProblem,
- prescribed_wake: bool | numpy.bool_ = True,
- free_wake: bool | numpy.bool_ = True,
- num_cycles_bounds: tuple[int, int] | None = None,
- num_chords_bounds: tuple[int, int] | None = None,
- panel_aspect_ratio_bounds: tuple[int, int] = (4, 1),
- num_chordwise_panels_bounds: tuple[int, int] = (3, 12),
- rtol: float | int = 0.05,
- atol: float | int = 0.001,
- coefficient_mask: tuple[bool, bool, bool, bool, bool, bool] | None = None,
- show_solver_progress: bool | numpy.bool_ = True,
- resolve_converged_solver: bool | numpy.bool_ = False,
- cache_path: str | pathlib.Path | None = None,
Finds the converged parameters of an UnsteadyProblem solved using the UnsteadyRingVortexLatticeMethodSolver.
Procedure:
Convergence is found by varying the UnsteadyRingVortexLatticeMethodSolver’s wake state (prescribed or free), the final length of the UnsteadyProblem’s wake (in number of chord lengths for static geometry or number of maximum-period motion cycles for variable geometry), the Airplanes’ Wings’ Panels’ aspect ratios, and the Airplanes’ Wings’ numbers of chordwise Panels. These values are iterated over via four nested loops. The outermost loop is the wake state. The next loop is the wake length. The loop after that is the Panel aspect ratios, and the innermost loop is the number of chordwise Panels.
With each new combination of these values, the UnsteadyProblem is solved, and each Airplane’s six final load coefficients are stored: the three force coefficients (in wind axes) and the three moment coefficients (in wind axes, relative to the first Airplane’s CG), or (cFX_W, cFY_W, cFZ_W, cMX_W_CgP1, cMY_W_CgP1, cMZ_W_CgP1). As this function deals with UnsteadyProblems, it considers the final load coefficients to be the final cycle’s mean load coefficients (the signed time-average over the final cycle) for UnsteadyProblems with variable geometry, and the final time step’s load coefficients for static geometry cases. Then, convergence is checked per coefficient between this iteration and the iterations with incrementally coarser meshes in all four parameter directions (wake state, wake length, Panel aspect ratio, and number of chordwise Panels). A coefficient is converged in a parameter direction when its absolute change from the coarser iteration is at most atol + rtol * max(abs(this), abs(coarser)). A parameter direction is converged when every unmasked coefficient of every Airplane is converged in that direction, so a multi- Airplane study converges only once all its Airplanes have.
If an iteration is converged in all four parameter directions, then we exit the nested for loops and return the converged parameters. However, the converged parameters are actually the values incrementally coarser than the final values, because refining from the coarser values to the final ones changed every unmasked coefficient by within the tolerance.
Notes:
There are two edge cases to this function. The first occurs when the user indicates that they only want check a single value for any of the four parameters (e.g. panel_aspect_ratio_bounds=(2, 2), both prescribed_wake=True and free_wake=False, etc.). Then, this parameter will not be iterated over, and convergence will only be checked for the other parameters.
The second edge case happens if the Panel aspect ratio has not converged at a value of 1 or if the wake state hasn’t converged once it’s set to a free wake. These conditions are the gold standards for Panel aspect ratio and wake state, so this function will return 1 for the converged value of Panel aspect ratio and a free wake for the converged wake state. In the code below, this state is referred to as a “saturated” Panel aspect ratio or wake state.
Each Wing is refined according to how its spanwise mesh was defined. A non-edge- defined Wing (one built from WingCrossSections) is refined by sweeping its number of spanwise Panels to hit the target Panel aspect ratio, holding its WingCrossSections fixed. An edge-defined Wing (one built from edge curves with Wing.from_edge_points) is refined by resampling its stored edge curves into the number of WingCrossSections that hits the target Panel aspect ratio, preserving its planform shape. An Airplane may hold both kinds of Wing at once. A Wing that has been exploded into single-panel strips cannot be refined and is rejected. Because resampling an edge-defined Wing changes its number of WingCrossSections, its WingCrossSectionMovements must all be static (the WingMovement’s own flapping and sweeping motion is preserved); a non- static WingCrossSectionMovement on an edge-defined Wing is rejected.
The time step is not a convergence parameter. Each iteration instead optimizes its own delta_time for its mesh with Movement’s iterative optimizer, so every solve uses the time step that is correct for its geometry and motion. The optimum depends only on the mesh, so it is computed once per Panel aspect ratio and number of chordwise Panels and reused across every wake state and wake length at that mesh.
- Parameters:
ref_problem – The UnsteadyProblem whose converged parameters will be found. This must be a standard UnsteadyProblem, not a FreeFlightUnsteadyProblem or an AeroelasticUnsteadyProblem, neither of which is supported. Its Movement must not truncate its wake, because this analysis sweeps the wake’s length, so its max_wake_rows, max_wake_chords, and max_wake_cycles parameters must all be None.
prescribed_wake – Determines if a prescribed wake state should be analyzed. If this parameter is False, then the
free_wakeparameter must be set to True. Can be a bool or a numpy bool and will be converted to a bool internally. The default is True.free_wake – Determines if a free wake state should be analyzed. If this parameter is False, then the
prescribed_wakeparameter must be set to True. Can be a bool or a numpy bool and will be converted to a bool internally. The default is True.num_cycles_bounds – For problems with non static geometry, determines the range of wake lengths (measured in number of maximum-period motion cycles) to simulate. For problems with static geometry, this must be None, and the
num_chords_boundsparameter will control the range of wake lengths instead. Otherwise, it must be a tuple of two positive ints with the first value less than or equal to the second value. Reasonable values range from 1 to 10, depending strongly on the Strouhal number. The default is None.num_chords_bounds – For problems with static geometry, determines the range of wake lengths (measured in number of reference chords) to simulate. For problems with non static geometry, it must be None, and the
num_cycles_boundsparameter will control the wake length instead. Otherwise, it must be a tuple of two positive ints with the first value less than or equal to the second value. Reasonable values range from 3 to 20. The default is None.panel_aspect_ratio_bounds – A tuple of two ints, in descending order, that determines the range of Panel aspect ratios to consider, from largest to smallest. This value dictates the Panels’ average y component length (in wing cross section parent axes) divided their average x component width (in wing cross section parent axes). Historically, these values range between 5 and 1. Values above 5 can be used for a coarser mesh, but the minimum value cannot be less than 1. The default is (4, 1).
num_chordwise_panels_bounds – A tuple of two ints, in ascending order, that determines the range of values to use for the Wings’ numbers of chordwise panels. The default is (3, 12).
rtol – A positive number (int or float) giving the relative tolerance for the per-coefficient convergence check. A coefficient is converged in a parameter direction when its absolute change from the incrementally coarser iteration is at most atol + rtol * max(abs(this), abs(coarser)). Set this smaller for a stricter convergence. Values are converted to floats internally. The default is 0.05.
atol – A positive number (int or float) giving the absolute tolerance floor for the per-coefficient convergence check. It keeps coefficients that sit near zero from being held to an unreachable relative tolerance. Values are converted to floats internally. The default is 0.001.
coefficient_mask – A tuple of six bools that determines which of the six load coefficients (cFX_W, cFY_W, cFZ_W, cMX_W_CgP1, cMY_W_CgP1, cMZ_W_CgP1, in that order) must converge, or None to require all six. At least one element must be True. Use this to ignore coefficients that are physically irrelevant to the analysis. The default is None.
show_solver_progress – Set this to True to show the TQDM progress bar during each run of the unsteady solver. For showing progress bars and displaying log statements, set up logging using the setup_logging function. It can be a bool or a numpy bool and will be converted internally to a bool. The default is True.
resolve_converged_solver – A bool for whether to recreate and run the solver at the converged parameters and return it. Because finding convergence is expensive, this defaults to False, in which case the returned solver is None. When True, the solver is rebuilt at the converged parameters (which are frequently coarser than the last iteration run) and run with streamlines calculated, so the returned solver is ready to use. The default is False.
cache_path – An optional path (a str or Path, which must end with “.json”) to a JSON file that caches each iteration’s solved load coefficients and solve time, keyed on the reference problem and the wake state, wake length, and mesh parameters, together with the mesh values it resolved (the spanwise Panel and WingCrossSection counts and the optimized delta_time). When given, an iteration already in the cache reuses those stored coefficients and values instead of re- running the solver and re-resolving the mesh, so a warm run also skips the delta_time optimizer, and each new iteration is written through to the file, so an interrupted or repeated study reuses the work it has already done. A cached iteration reports its stored solve time, so a warm run’s convergence report still shows how long the converged mesh took to solve. An iteration whose coefficients and values are all cached also skips building its meshed problem, which avoids regenerating the geometry at every time step. The mesh values are keyed on the absolute mesh rather than a sweep index, so a later run over different bounds still reuses any iteration it shares. When None, no cache is read or written. The default is None.
- Returns:
A tuple of one bool, three ints, and a solver, or a tuple of five Nones. In order, the first four elements are the converged wake state (prescribed=True and free=False), the converged wake length (in number of cycles for non static geometries and number of chords for static geometries), the converged Panel aspect ratio, and the converged number of chordwise Panels. The fifth element is the converged solver if resolve_converged_solver is True, otherwise None. If the function could not find a set of converged parameters, it returns (None, None, None, None, None).