From f59515110cc7cf2d3b9652c65c9d3228a695f252 Mon Sep 17 00:00:00 2001 From: A-CGray Date: Fri, 4 Oct 2024 13:34:24 -0700 Subject: [PATCH 1/6] NAS debugging stuff --- adflow/mphys/mphys_adflow.py | 112 ++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/adflow/mphys/mphys_adflow.py b/adflow/mphys/mphys_adflow.py index 7d1a497e3..1a925d681 100644 --- a/adflow/mphys/mphys_adflow.py +++ b/adflow/mphys/mphys_adflow.py @@ -13,7 +13,7 @@ # Set this to true to print out the name of the function being called and the class it's being called from along with # printing messages when node coordinates and states are updated from OpenMDAO inputs and outputs. -DEBUG_LOGGING = False +DEBUG_LOGGING = True def print_func_call(component): @@ -491,6 +491,8 @@ def _setup_vectors(self, root_vectors): self.set_val("adflow_states", self.solver.getStates()) def apply_nonlinear(self, inputs, outputs, residuals): + if DEBUG_LOGGING: + print_func_call(self) solver = self.solver ap = self.ap setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) @@ -498,6 +500,15 @@ def apply_nonlinear(self, inputs, outputs, residuals): # flow residuals residuals["adflow_states"] = solver.getResidual(ap) + def printStatesRange(self, states): + stateNames = ["density", "velocityX", "velocityY", "velocityZ", "Energy", "Turb"] + for ii, stateName in enumerate(stateNames): + singleState = states[ii::6] + minState = self.comm.allreduce(np.min(singleState), op=MPI.MIN) + maxState = self.comm.allreduce(np.max(singleState), op=MPI.MAX) + if self.comm.rank == 0: + print(f"{stateName}: min = {minState:.11e}, max = {maxState:.11e}") + def solve_nonlinear(self, inputs, outputs): if DEBUG_LOGGING: print_func_call(self) @@ -505,13 +516,108 @@ def solve_nonlinear(self, inputs, outputs): ap = self.ap if self._do_solve: + + if self.comm.rank == 0: + print(f"Pre-setAeroProblem, OpenMDAO outputs") + self.printStatesRange(outputs["adflow_states"]) + if self.comm.rank == 0: + print(f"Pre-setAeroProblem, ADflow state") + self.printStatesRange(solver.getStates()) + setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) ap.solveFailed = False # might need to clear this out? ap.fatalFail = False + if self.comm.rank == 0: + print(f"Post-setAeroProblem, OpenMDAO outputs") + self.printStatesRange(outputs["adflow_states"]) + if self.comm.rank == 0: + print(f"Post-setAeroProblem, ADflow state") + self.printStatesRange(solver.getStates()) + + # ============================================================================== + # TODO: Remove this once done debugging + # ============================================================================== + # Check if there is a NaN in any of the inputs or outputs + # for variable in inputs: + # nanInInput = self.comm.allreduce(any(np.isnan(inputs[variable])), op=MPI.LOR) + # if self.comm.rank == 0: + # if nanInInput: + # print(f"NaN present in {variable} input!") + # else: + # print(f"No NaNs in {variable} input") + # for variable in outputs: + # nanInOutput = self.comm.allreduce(any(np.isnan(outputs[variable])), op=MPI.LOR) + # if self.comm.rank == 0: + # if nanInOutput: + # print(f"NaN present in {variable} output!") + # else: + # print(f"No NaNs in {variable} output") + + # # Do a standalone residual evaluation + # if self.comm.rank == 0: + # print(f"Pre-residualEval, OpenMDAO outputs") + # self.printStatesRange(outputs["adflow_states"]) + # if self.comm.rank == 0: + # print(f"Pre-residualEval, ADflow state") + # self.printStatesRange(solver.getStates()) + + + # solver.writeSolution(baseName=f"{self.ap.name}_preResEval", number=self.solution_counter) + res = solver.getResidual(ap) + # if self.comm.rank == 0: + # print(f"Post-residualEval, OpenMDAO outputs") + # self.printStatesRange(outputs["adflow_states"]) + # if self.comm.rank == 0: + # print(f"Post-residualEval, ADflow state") + # self.printStatesRange(solver.getStates()) + # solver.writeSolution(baseName=f"{self.ap.name}_postResEval", number=self.solution_counter) + # self.solution_counter += 1 + + nanInResidual = self.comm.allreduce(any(np.isnan(res)), op=MPI.LOR) + if self.comm.rank == 0: + if nanInResidual: + print("NaN present in residual") + else: + print("No NaNs in residual") + + if nanInResidual: + # Add a small amount of noise (+- 1e-4 times the average magnitude of that state) to the adflow state before setting it + # for ii in range(6): + # singleState = outputs["adflow_states"][ii::6] + # avgMag = np.mean(np.abs(singleState)) + # outputs["adflow_states"][ii::6] += 1e-4*avgMag * (np.random.rand(len(singleState))-0.5) + # setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) + + # Reset the solution + solver.resetFlow(ap) + + # if self.comm.rank == 0: + # print(f"Pre-solve, OpenMDAO outputs") + # self.printStatesRange(outputs["adflow_states"]) + # if self.comm.rank == 0: + # print(f"Pre-solve, ADflow state") + # self.printStatesRange(solver.getStates()) + # ============================================================================== + # end Remove + # ============================================================================== + # do not write solution files inside the solver loop solver(ap, writeSolution=False) + # ============================================================================== + # TODO: Remove this once done debugging + # ============================================================================== + # if self.comm.rank == 0: + # print(f"Post-solve, OpenMDAO outputs") + # self.printStatesRange(outputs["adflow_states"]) + # if self.comm.rank == 0: + # print(f"Post-solve, ADflow state") + # self.printStatesRange(solver.getStates()) + # ============================================================================== + # end Remove + # ============================================================================== + # base name for failed solution writing fail_name = f"{self.ap.name}_analysis_fail" @@ -521,6 +627,10 @@ def solve_nonlinear(self, inputs, outputs): print("# Solve Fatal Fail. Analysis Error") print("###############################################################") + # write the solution so that we can diagnose + solver.writeSolution(baseName=fail_name, number=self.solution_counter) + self.solution_counter += 1 + raise AnalysisError("ADFLOW Solver Fatal Fail") if ap.solveFailed: From c097132a2e46b8357ad431cc9da61f206ecf4852 Mon Sep 17 00:00:00 2001 From: Kevin Jacobson Date: Wed, 11 Dec 2024 08:53:58 -0500 Subject: [PATCH 2/6] Changes to mphys wrapper to acccount for MPhys 2.0.0 --- adflow/mphys/mphys_adflow.py | 75 ++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/adflow/mphys/mphys_adflow.py b/adflow/mphys/mphys_adflow.py index 7d1a497e3..c9631977e 100644 --- a/adflow/mphys/mphys_adflow.py +++ b/adflow/mphys/mphys_adflow.py @@ -4,7 +4,7 @@ import numpy as np from adflow import ADFLOW from idwarp import USMesh, MultiUSMesh -from mphys.builder import Builder +from mphys import Builder, MPhysVariables from openmdao.api import AnalysisError, ExplicitComponent, Group, ImplicitComponent from mpi4py import MPI @@ -16,6 +16,13 @@ DEBUG_LOGGING = False +X_AERO0 = MPhysVariables.Aerodynamics.Surface.COORDINATES_INITIAL +X_AERO = MPhysVariables.Aerodynamics.Surface.COORDINATES +X_AERO0_MESH = MPhysVariables.Aerodynamics.Surface.Mesh.COORDINATES +X_AERO0_GEOM_OUTPUT = MPhysVariables.Aerodynamics.Surface.Geometry.COORDINATES_OUTPUT +F_AERO = MPhysVariables.Aerodynamics.Surface.LOADS +Q_AERO = MPhysVariables.Aerodynamics.Surface.HEAT_FLOW + def print_func_call(component): """Prints the name of the class and function being. Useful for debugging when you want to see what order OpenMDAO is calling things in. @@ -93,8 +100,8 @@ def set_surf_coords(solver, inputs): True on all procs if the coordinates were updated on any proc, False otherwise. """ coordsUpdated = False - if "x_aero" in inputs: - newSurfCoord = inputs["x_aero"].reshape((-1, 3)) + if X_AERO in inputs: + newSurfCoord = inputs[X_AERO].reshape((-1, 3)) # We take coordinates directly from IDWarp because they are guaranteed to match the coordinates we set. The # coordinates returned by solver.getSurfaceCoordinates are taken from the volume coordinate data structures and @@ -231,7 +238,7 @@ def setup(self): coord_size = self.x_a0.size self.add_output( - "x_aero0", + X_AERO0_MESH, distributed=True, shape=coord_size, desc="initial aerodynamic surface node coordinates", @@ -240,11 +247,11 @@ def setup(self): def mphys_add_coordinate_input(self): self.add_input( - "x_aero0_points", distributed=True, shape_by_conn=True, desc="aerodynamic surface with geom changes" + X_AERO0_GEOM_OUTPUT, distributed=True, shape_by_conn=True, desc="aerodynamic surface with geom changes" ) # return the promoted name and coordinates - return "x_aero0_points", self.x_a0 + return X_AERO0_GEOM_OUTPUT, self.x_a0 def mphys_get_surface_mesh(self): return self.x_a0 @@ -321,20 +328,20 @@ def _getTriangulatedMeshSurface(self, groupName=None, **kwargs): def compute(self, inputs, outputs): if DEBUG_LOGGING: print_func_call(self) - if "x_aero0_points" in inputs: - outputs["x_aero0"] = inputs["x_aero0_points"] + if X_AERO0_GEOM_OUTPUT in inputs: + outputs[X_AERO0_MESH] = inputs[X_AERO0_GEOM_OUTPUT] else: - outputs["x_aero0"] = self.x_a0 + outputs[X_AERO0_MESH] = self.x_a0 def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): if DEBUG_LOGGING: print_func_call(self) if mode == "fwd": - if "x_aero0_points" in d_inputs: - d_outputs["x_aero0"] += d_inputs["x_aero0_points"] + if X_AERO0_GEOM_OUTPUT in d_inputs: + d_outputs[X_AERO0_MESH] += d_inputs[X_AERO0_GEOM_OUTPUT] elif mode == "rev": - if "x_aero0_points" in d_inputs: - d_inputs["x_aero0_points"] += d_outputs["x_aero0"] + if X_AERO0_GEOM_OUTPUT in d_inputs: + d_inputs[X_AERO0_GEOM_OUTPUT] += d_outputs[X_AERO0_MESH] class ADflowWarper(ExplicitComponent): @@ -359,7 +366,7 @@ def setup(self): # state inputs and outputs local_volume_coord_size = solver.mesh.getSolverGrid().size - self.add_input("x_aero", distributed=True, shape_by_conn=True, tags=["mphys_coupling"]) + self.add_input(X_AERO, distributed=True, shape_by_conn=True, tags=["mphys_coupling"]) self.add_output("adflow_vol_coords", distributed=True, shape=local_volume_coord_size, tags=["mphys_coupling"]) # self.declare_partials(of='adflow_vol_coords', wrt='x_aero') @@ -384,21 +391,21 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): if mode == "fwd": if "adflow_vol_coords" in d_outputs: - if "x_aero" in d_inputs: - dxS = d_inputs["x_aero"] + if X_AERO in d_inputs: + dxS = d_inputs[X_AERO] dxV = self.solver.mesh.warpDerivFwd(dxS) d_outputs["adflow_vol_coords"] += dxV elif mode == "rev": if "adflow_vol_coords" in d_outputs: - if "x_aero" in d_inputs: + if X_AERO in d_inputs: dxV = d_outputs["adflow_vol_coords"] self.solver.mesh.warpDeriv(dxV) dxS = self.solver.mesh.getdXs() dxS = self.solver.mapVector( dxS, self.solver.meshFamilyGroup, self.solver.designFamilyGroup, includeZipper=True ) - d_inputs["x_aero"] += dxS.flatten() + d_inputs[X_AERO] += dxS.flatten() class ADflowSolver(ImplicitComponent): @@ -719,7 +726,7 @@ def setup(self): self.add_input("adflow_states", distributed=True, shape_by_conn=True, tags=["mphys_coupling"]) local_surface_coord_size = solver.getSurfaceCoordinates(includeZipper=True).size - self.add_output("f_aero", distributed=True, shape=local_surface_coord_size, tags=["mphys_coupling"]) + self.add_output(F_AERO, distributed=True, shape=local_surface_coord_size, tags=["mphys_coupling"]) # self.declare_partials(of='f_aero', wrt='*') @@ -747,7 +754,7 @@ def compute(self, inputs, outputs): setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) f_aero = solver.getForces() - outputs["f_aero"] = f_aero.flatten(order="C") + outputs[F_AERO] = f_aero.flatten(order="C") def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): if DEBUG_LOGGING: @@ -762,7 +769,7 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): solver.getResidual(ap) if mode == "fwd": - if "f_aero" in d_outputs: + if F_AERO in d_outputs: xDvDot = {} for var_name in d_inputs: xDvDot[var_name] = d_inputs[var_name] @@ -776,11 +783,11 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): xVDot = None if not (xVDot is None and wDot is None): dfdot = solver.computeJacobianVectorProductFwd(xDvDot=xDvDot, xVDot=xVDot, wDot=wDot, fDeriv=True) - d_outputs["f_aero"] += dfdot.flatten() + d_outputs[F_AERO] += dfdot.flatten() elif mode == "rev": - if "f_aero" in d_outputs: - fBar = d_outputs["f_aero"] + if F_AERO in d_outputs: + fBar = d_outputs[F_AERO] wBar, xVBar, xDVBar = solver.computeJacobianVectorProductBwd( fBar=fBar, wDeriv=True, xVDeriv=True, xDvDeriv=False, xDvDerivAero=True @@ -817,7 +824,7 @@ def setup(self): self.add_input("adflow_states", distributed=True, shape_by_conn=True, tags=["mphys_coupling"]) self.add_output( - "q_convect", + Q_AERO, distributed=True, val=np.ones(local_nodes) * -499, shape=local_nodes, @@ -855,7 +862,7 @@ def compute(self, inputs, outputs): if updatesMade: solver.getResidual(ap) - outputs["q_convect"] = solver.getHeatFluxes().flatten(order="C") + outputs[Q_AERO] = solver.getHeatFluxes().flatten(order="C") # print() def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): @@ -871,7 +878,7 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): solver.getResidual(ap) if mode == "fwd": - if "q_convect" in d_outputs: + if Q_AERO in d_outputs: xDvDot = {} for var_name in d_inputs: xDvDot[var_name] = d_inputs[var_name] @@ -891,11 +898,11 @@ def compute_jacvec_product(self, inputs, d_inputs, d_outputs, mode): dhfdot_map, self.solver.allWallsGroup, self.solver.allIsothermalWallsGroup ) dhfdot = dhfdot_map[:, 0] - d_outputs["q_convect"] += dhfdot + d_outputs[Q_AERO] += dhfdot elif mode == "rev": - if "q_convect" in d_outputs: - hfBar = d_outputs["q_convect"] + if Q_AERO in d_outputs: + hfBar = d_outputs[Q_AERO] hfBar_map = np.zeros((hfBar.size, 3)) hfBar_map[:, 0] = hfBar.flatten() @@ -1219,7 +1226,7 @@ def setup(self): ADflowWarper( aero_solver=self.aero_solver, ), - promotes_inputs=["x_aero"], + promotes_inputs=[X_AERO], promotes_outputs=["adflow_vol_coords"], ) @@ -1240,7 +1247,7 @@ def setup(self): "force", ADflowForces(aero_solver=self.aero_solver), promotes_inputs=["adflow_vol_coords", "adflow_states"], - promotes_outputs=["f_aero"], + promotes_outputs=[F_AERO], ) if self.prop_coupling: self.add_subsystem( @@ -1255,7 +1262,7 @@ def setup(self): if self.heat_transfer: self.add_subsystem( - "heat_xfer", AdflowHeatTransfer(aero_solver=self.aero_solver), promotes_outputs=["q_convect"] + "heat_xfer", AdflowHeatTransfer(aero_solver=self.aero_solver), promotes_outputs=[Q_AERO] ) if balance_group is not None: @@ -1306,7 +1313,7 @@ def setup(self): self.add_subsystem( "volume_mesh", ADflowWarper(aero_solver=aero_solver), - promotes_inputs=[("x_aero", "x_aero0")], + promotes_inputs=[(X_AERO, X_AERO0)], promotes_outputs=["adflow_vol_coords"], ) From e2c99e84cdaf624c4edf87538af85983b311c1a4 Mon Sep 17 00:00:00 2001 From: A-CGray Date: Tue, 14 Jan 2025 14:02:14 -0800 Subject: [PATCH 3/6] Cleaning up hacky fix for random solver failures --- adflow/mphys/mphys_adflow.py | 62 ++---------------------------------- 1 file changed, 2 insertions(+), 60 deletions(-) diff --git a/adflow/mphys/mphys_adflow.py b/adflow/mphys/mphys_adflow.py index 1a925d681..7b13bb938 100644 --- a/adflow/mphys/mphys_adflow.py +++ b/adflow/mphys/mphys_adflow.py @@ -517,62 +517,10 @@ def solve_nonlinear(self, inputs, outputs): if self._do_solve: - if self.comm.rank == 0: - print(f"Pre-setAeroProblem, OpenMDAO outputs") - self.printStatesRange(outputs["adflow_states"]) - if self.comm.rank == 0: - print(f"Pre-setAeroProblem, ADflow state") - self.printStatesRange(solver.getStates()) - setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) ap.solveFailed = False # might need to clear this out? ap.fatalFail = False - - if self.comm.rank == 0: - print(f"Post-setAeroProblem, OpenMDAO outputs") - self.printStatesRange(outputs["adflow_states"]) - if self.comm.rank == 0: - print(f"Post-setAeroProblem, ADflow state") - self.printStatesRange(solver.getStates()) - - # ============================================================================== - # TODO: Remove this once done debugging - # ============================================================================== - # Check if there is a NaN in any of the inputs or outputs - # for variable in inputs: - # nanInInput = self.comm.allreduce(any(np.isnan(inputs[variable])), op=MPI.LOR) - # if self.comm.rank == 0: - # if nanInInput: - # print(f"NaN present in {variable} input!") - # else: - # print(f"No NaNs in {variable} input") - # for variable in outputs: - # nanInOutput = self.comm.allreduce(any(np.isnan(outputs[variable])), op=MPI.LOR) - # if self.comm.rank == 0: - # if nanInOutput: - # print(f"NaN present in {variable} output!") - # else: - # print(f"No NaNs in {variable} output") - - # # Do a standalone residual evaluation - # if self.comm.rank == 0: - # print(f"Pre-residualEval, OpenMDAO outputs") - # self.printStatesRange(outputs["adflow_states"]) - # if self.comm.rank == 0: - # print(f"Pre-residualEval, ADflow state") - # self.printStatesRange(solver.getStates()) - - - # solver.writeSolution(baseName=f"{self.ap.name}_preResEval", number=self.solution_counter) res = solver.getResidual(ap) - # if self.comm.rank == 0: - # print(f"Post-residualEval, OpenMDAO outputs") - # self.printStatesRange(outputs["adflow_states"]) - # if self.comm.rank == 0: - # print(f"Post-residualEval, ADflow state") - # self.printStatesRange(solver.getStates()) - # solver.writeSolution(baseName=f"{self.ap.name}_postResEval", number=self.solution_counter) - # self.solution_counter += 1 nanInResidual = self.comm.allreduce(any(np.isnan(res)), op=MPI.LOR) if self.comm.rank == 0: @@ -582,15 +530,9 @@ def solve_nonlinear(self, inputs, outputs): print("No NaNs in residual") if nanInResidual: - # Add a small amount of noise (+- 1e-4 times the average magnitude of that state) to the adflow state before setting it - # for ii in range(6): - # singleState = outputs["adflow_states"][ii::6] - # avgMag = np.mean(np.abs(singleState)) - # outputs["adflow_states"][ii::6] += 1e-4*avgMag * (np.random.rand(len(singleState))-0.5) - # setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) - - # Reset the solution + # Reset the solution then set the inputs and states again, somehow this fixes the issue solver.resetFlow(ap) + setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) # if self.comm.rank == 0: # print(f"Pre-solve, OpenMDAO outputs") From 1d515e06a494e43dbbe93400474067db26bec1b1 Mon Sep 17 00:00:00 2001 From: A-CGray Date: Tue, 14 Jan 2025 14:10:07 -0800 Subject: [PATCH 4/6] Cleaning up fix again --- adflow/mphys/mphys_adflow.py | 41 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/adflow/mphys/mphys_adflow.py b/adflow/mphys/mphys_adflow.py index 7b13bb938..2f0a3f5a1 100644 --- a/adflow/mphys/mphys_adflow.py +++ b/adflow/mphys/mphys_adflow.py @@ -520,6 +520,24 @@ def solve_nonlinear(self, inputs, outputs): setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) ap.solveFailed = False # might need to clear this out? ap.fatalFail = False + + # For some reason, the ADflow solver will randomly NaN in the first iteration of a solve when starting from a state and mesh that it has already converged successfully. I have tried many things to debug this but nothing has worked: + # - Explicitly setting state before solve + # - compiling with `-O1 -xCORE-AVX2` + # - Compiling with `-fp-model=precise` + # - Compiling with only `-O2` + # - Disabling blockettes + # - running with a different number of procs + # - Running on `cas_ait` instead of `sky_ele` nodes + # - As above but setting slightly perturbed states + # - Running on a different mesh + # - Running on stampede + + # The thing I have found to work is: + # - Set the OpenMDAO inputs and outputs + # - Evaluate the residual + # - If there is a NaN in the residual, call `resetFlow` and set the same OpenMDAO inputs and outputs again + # - Run the solver res = solver.getResidual(ap) nanInResidual = self.comm.allreduce(any(np.isnan(res)), op=MPI.LOR) @@ -534,32 +552,9 @@ def solve_nonlinear(self, inputs, outputs): solver.resetFlow(ap) setAeroProblem(solver, ap, self.ap_vars, inputs=inputs, outputs=outputs, print_dict=False) - # if self.comm.rank == 0: - # print(f"Pre-solve, OpenMDAO outputs") - # self.printStatesRange(outputs["adflow_states"]) - # if self.comm.rank == 0: - # print(f"Pre-solve, ADflow state") - # self.printStatesRange(solver.getStates()) - # ============================================================================== - # end Remove - # ============================================================================== - # do not write solution files inside the solver loop solver(ap, writeSolution=False) - # ============================================================================== - # TODO: Remove this once done debugging - # ============================================================================== - # if self.comm.rank == 0: - # print(f"Post-solve, OpenMDAO outputs") - # self.printStatesRange(outputs["adflow_states"]) - # if self.comm.rank == 0: - # print(f"Post-solve, ADflow state") - # self.printStatesRange(solver.getStates()) - # ============================================================================== - # end Remove - # ============================================================================== - # base name for failed solution writing fail_name = f"{self.ap.name}_analysis_fail" From 91923ff245a064f5c68009730835a76ec4c96bb0 Mon Sep 17 00:00:00 2001 From: Alasdair Gray Date: Wed, 20 Aug 2025 16:50:20 -0400 Subject: [PATCH 5/6] Test ruff formatting and linting --- .github/workflows/format-and-lint.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/format-and-lint.yaml diff --git a/.github/workflows/format-and-lint.yaml b/.github/workflows/format-and-lint.yaml new file mode 100644 index 000000000..5607a79c4 --- /dev/null +++ b/.github/workflows/format-and-lint.yaml @@ -0,0 +1,12 @@ +name: Format and Lint + +on: + push: + branches: [main] + tags: + - v*.*.* + pull_request: + +jobs: + pre-commit: + uses: mdolab/.github/.github/workflows/format-and-lint.yaml@ruffConfig From e83695196ed6a3ffb9b86af081c3a06cd3495d29 Mon Sep 17 00:00:00 2001 From: Alasdair Gray Date: Wed, 20 Aug 2025 16:51:08 -0400 Subject: [PATCH 6/6] Convert local flake8 config to ruff --- ruff.toml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 ruff.toml diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..c20358d82 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,8 @@ +extend-exclude =[ + "src/build/fort_depend.py", + "src/adjoint/autoEdit/autoEdit*.py", + "src_cs/build/complexify.py", + "adflow/pyWeightAndBalance.py", + "adflow/pyWingCG.py", + "adflow/om_*.py", +]