diff --git a/.github/workflows/code_cov.yml b/.github/workflows/code_cov.yml index 76f9e3f8..7de2e01d 100644 --- a/.github/workflows/code_cov.yml +++ b/.github/workflows/code_cov.yml @@ -8,19 +8,13 @@ env: DOCKER_MOUNT_DIR: '/home/dafoamuser/mount/$REPO_NAME' DOCKER_TAG: 'v4' DOCKER_ENV_FILE: '/home/dafoamuser/dafoam/loadDAFoam.sh' + DOCKER_OF_ADF_BASHRC: '/home/dafoamuser/dafoam/OpenFOAM/OpenFOAM-v1812-ADF/etc/bashrc' + DOCKER_OF_ADR_BASHRC: '/home/dafoamuser/dafoam/OpenFOAM/OpenFOAM-v1812-ADR/etc/bashrc' jobs: code_coverage: runs-on: ubuntu-20.04 name: Codecov - strategy: - fail-fast: false - matrix: - testConfig: [incompressible] - include: - - testConfig: incompressible - args: 'incompressible' - steps: - uses: actions/checkout@main - name: Create the docker container and run the tests @@ -28,13 +22,11 @@ jobs: docker pull dafoam/opt-packages:${{env.DOCKER_TAG}} docker run -i -d -u dafoamuser --name regtest -v $GITHUB_WORKSPACE:${{env.DOCKER_MOUNT_DIR}} dafoam/opt-packages:${{env.DOCKER_TAG}} /bin/bash docker exec -i regtest /bin/bash -c "rm -rf ${{env.DOCKER_WORKING_DIR}} && cp -r ${{env.DOCKER_MOUNT_DIR}} ${{env.DOCKER_WORKING_DIR}}" - docker exec regtest sed -i 's/-std=c++11/-std=c++11 -fprofile-arcs -ftest-coverage/g' ${{env.DOCKER_WORKING_DIR}}/src/adjoint/DAOption/Make/options - docker exec regtest sed -i 's/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX)/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX) -lgcov/g' ${{env.DOCKER_WORKING_DIR}}/src/adjoint/DAOption/Make/options - docker exec regtest sed -i 's/-std=c++11/-std=c++11 -fprofile-arcs -ftest-coverage/g' ${{env.DOCKER_WORKING_DIR}}/src/adjoint/DAUtility/Make/options - docker exec regtest sed -i 's/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX)/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX) -lgcov/g' ${{env.DOCKER_WORKING_DIR}}/src/adjoint/DAUtility/Make/options + docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}}/src && . ./.add_coverage_flag.sh" docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}} && ./Allmake" - docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}} && pip install ." - docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}}/tests && ./Allrun" + docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && . ${{env.DOCKER_OF_ADR_BASHRC}} && cd ${{env.DOCKER_WORKING_DIR}} && ./Allmake 2> log && pip install ." + docker exec -i -e DF_CHECK_COVERAGE=1 regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}}/tests && ./Allrun" + docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}}/tests && coverage combine && coverage xml && echo dafoamuser | sudo -S cp -r coverage.xml ${{env.DOCKER_MOUNT_DIR}}/" docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}} && lcov --capture --directory . --output-file coverage.info && echo dafoamuser | sudo -S cp -r coverage.info ${{env.DOCKER_MOUNT_DIR}}/" - name: Upload uses: codecov/codecov-action@v4 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6676839f..9e7c65ec 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,13 +16,6 @@ jobs: reg_tests: runs-on: ubuntu-20.04 name: Tests - strategy: - fail-fast: false - matrix: - testConfig: [incompressible] - include: - - testConfig: incompressible - args: 'incompressible' steps: - uses: actions/checkout@v3 - name: Create the docker container and run the tests @@ -31,5 +24,5 @@ jobs: docker run -i -d -u dafoamuser --name regtest -v $GITHUB_WORKSPACE:${{env.DOCKER_MOUNT_DIR}} dafoam/opt-packages:${{env.DOCKER_TAG}} /bin/bash docker exec -i regtest /bin/bash -c "rm -rf ${{env.DOCKER_WORKING_DIR}} && cp -r ${{env.DOCKER_MOUNT_DIR}} ${{env.DOCKER_WORKING_DIR}}" docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}} && ./Allmake" - docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && . ${{env.DOCKER_OF_ADR_BASHRC}} && cd ${{env.DOCKER_WORKING_DIR}} && ./Allmake && pip install ." + docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && . ${{env.DOCKER_OF_ADR_BASHRC}} && cd ${{env.DOCKER_WORKING_DIR}} && ./Allmake 2> log && pip install ." docker exec -i regtest /bin/bash -c ". ${{env.DOCKER_ENV_FILE}} && cd ${{env.DOCKER_WORKING_DIR}}/tests && ./Allrun" diff --git a/dafoam/mphys/mphys_dafoam.py b/dafoam/mphys/mphys_dafoam.py index fce449b3..f6306543 100644 --- a/dafoam/mphys/mphys_dafoam.py +++ b/dafoam/mphys/mphys_dafoam.py @@ -756,9 +756,20 @@ def solve_nonlinear(self, inputs, outputs): DASolver.setThermal(q_conduct) else: raise AnalysisError("discipline not valid!") + + # before running the primal, we need to check if the mesh + # quality is good + meshOK = DASolver.solver.checkMesh() # solve the flow with the current design variable - DASolver() + # if the mesh is not OK, do not run the primal + if meshOK: + DASolver() + else: + DASolver.primalFail = 1 + + # after solving the primal, we need to print its residual info + DASolver.solver.calcPrimalResidualStatistics("print".encode()) # get the objective functions funcs = {} diff --git a/src/.add_coverage_flag.sh b/src/.add_coverage_flag.sh new file mode 100644 index 00000000..c496a868 --- /dev/null +++ b/src/.add_coverage_flag.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +sed -i 's/-std=c++11/-std=c++11 -fprofile-arcs -ftest-coverage/g' adjoint/*/Make/options +sed -i 's/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX)/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX) -lgcov/g' adjoint/*/Make/options + +sed -i 's/-std=c++11/-std=c++11 -fprofile-arcs -ftest-coverage/g' pyDASolvers/Make/options +sed -i 's/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX)/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX) -lgcov/g' pyDASolvers/Make/options + +sed -i 's/-std=c++11/-std=c++11 -fprofile-arcs -ftest-coverage/g' utilities/coloring/Make/options +sed -i 's/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX)/-lfiniteVolume$(WM_CODI_AD_LIB_POSTFIX) -lgcov/g' utilities/coloring/Make/options diff --git a/src/adjoint/models/Make/files b/src/adjoint/models/Make/files index 1d02335c..3650e726 100755 --- a/src/adjoint/models/Make/files +++ b/src/adjoint/models/Make/files @@ -1,5 +1,6 @@ MRFDF/MRFZoneDF.C MRFDF/MRFZoneListDF.C MRFDF/IOMRFZoneListDF.C +meshWaveFrozen/meshWaveFrozenPatchDistMethod.C LIB = $(DAFOAM_ROOT_PATH)/OpenFOAM/sharedLibs/libDAMisc$(WM_CODI_AD_LIB_POSTFIX) diff --git a/tests/Allrun b/tests/Allrun index 02dbc4f5..59d36ba8 100755 --- a/tests/Allrun +++ b/tests/Allrun @@ -13,11 +13,68 @@ else wget https://github.com/DAFoam/reg_test_files/archive/refs/heads/main.tar.gz -O reg_test_files-main.tar.gz --no-check-certificate fi -function runUnitTests() +function runRegTests() { - rm -rf reg_test_files-main + rm -rf reg_test_files-main DAFoam_Test_${1}.txt tar -zxf reg_test_files-main.tar.gz - mpirun --oversubscribe -np 4 python runUnitTests_${1}.py + if [ -z "$DF_CHECK_COVERAGE" ]; then + mpirun --oversubscribe -np 4 python runRegTests_${1}.py $@ | tee DAFoam_Test_${1}.txt + if [ "${PIPESTATUS[0]}" -ne "0" ]; then + echo "${1}: Failed!" + exit 1 + fi + # need to replace the "[0m" for mphys tests + sed -i 's/\[0m//g' DAFoam_Test_${1}.txt + sed -i 's/[^[:print:]\t]//g' DAFoam_Test_${1}.txt + python testFuncs.py refs/DAFoam_Test_${1}Ref.txt DAFoam_Test_${1}.txt + if [ "$?" -ne "0" ]; then + echo "${1}: Failed!" + exit 1 + else + echo "${1}: Success!" + fi + elif [ "$DF_CHECK_COVERAGE" = "1" ]; then + mpirun --oversubscribe -np 4 coverage run runRegTests_${1}.py $@ | tee DAFoam_Test_${1}.txt + if [ "${PIPESTATUS[0]}" -ne "0" ]; then + echo "${1}: Failed!" + exit 1 + fi + echo "DF_CHECK_COVERAGE key found! Do NOT check the regression test values!" + else + echo "DF_CHECK_COVERAGE key not valid! Set it to 1!" + exit 1 + fi } -runUnitTests DAUtility +function runUnitTests() +{ + rm -rf reg_test_files-main DAFoam_Test_${1}.txt + tar -zxf reg_test_files-main.tar.gz + mpirun --oversubscribe -np 4 python runUnitTests_${1}.py +} + +# Find all files matching the regression test script pattern +for file in runRegTests_*.py; do + # Check if the file exists to avoid wildcard issues + if [[ -f "$file" ]]; then + # Extract the part between "runRegTests_" and ".py" + extracted_name="${file#runRegTests_}" + extracted_name="${extracted_name%.py}" + + # run the regression tests + runRegTests "$extracted_name" + fi +done + +# Find all files matching the unit test script pattern +for file in runUnitTests_*.py; do + # Check if the file exists to avoid wildcard issues + if [[ -f "$file" ]]; then + # Extract the part between "runUnitTests_" and ".py" + extracted_name="${file#runUnitTests_}" + extracted_name="${extracted_name%.py}" + + # run the regression tests + runUnitTests "$extracted_name" + fi +done diff --git a/tests/refs/DAFoam_Test_DASimpleFoamRef.txt b/tests/refs/DAFoam_Test_DASimpleFoamRef.txt index 0899401c..85e8afb1 100755 --- a/tests/refs/DAFoam_Test_DASimpleFoamRef.txt +++ b/tests/refs/DAFoam_Test_DASimpleFoamRef.txt @@ -1,121 +1,14 @@ Dictionary Key: CD -@value 0.01438365115696084 1e-08 1e-10 +@value 0.01707374542774201 1e-10 1e-12 Dictionary Key: CL -@value 0.5278433423293855 1e-08 1e-10 -Dictionary Key: CMZ -@value -0.006992993721841563 1e-08 1e-10 -Dictionary Key: THRUST -@value 0.3964124860392292 1e-08 1e-10 -Dictionary Key: VOL -@value 32.90556883062804 1e-08 1e-10 -Dictionary Key: fail -@value 0 1e-08 1e-10 -Dictionary Key: forces -@value 0.449611137104235 1e-08 1e-10 -Dictionary Key: CD -Dictionary Key: actuator -@value 0.002692654743062405 1e-04 1e-06 -@value -0.0003473341347664285 1e-04 1e-06 -@value 5.620234383570104e-05 1e-04 1e-06 -@value 0 0.0001 1e-06 -@value -0.00277322483067405 0.0001 1e-06 -@value -1.890611842632963e-07 0.0001 1e-06 -@value -0.005953704788967595 1e-04 1e-06 -@value 9.593947158077255e-05 1e-04 1e-06 -@value 1.956078536327928e-05 1e-04 1e-06 -@value 1.534919864800157e-08 1e-04 1e-06 -@value -0.001740961838225806 1e-04 1e-06 -@value -0.001285589164731539 1e-04 1e-06 -@value 0 0.0001 1e-06 -Dictionary Key: alpha -@value 0.003478846233720689 1e-04 1e-06 -Dictionary Key: shapey -@value -0.01145880278936309 1e-04 1e-06 -@value 0.04946171930909396 1e-04 1e-06 -@value 0.09099507726500972 1e-04 1e-06 +@value 0.2998610077528413 1e-10 1e-12 Dictionary Key: CL -Dictionary Key: actuator -@value -0.01775995579432492 1e-04 1e-06 -@value 0.1160533063360002 1e-04 1e-06 -@value 0.00188311916616678 1e-04 1e-06 -@value 0 0.0001 1e-06 -@value 0.02316872166184394 0.0001 1e-06 -@value -6.046074582706222e-07 0.0001 1e-06 -@value -0.1581267547150706 1e-04 1e-06 -@value -0.03433514066432578 1e-04 1e-06 -@value 0.0002027111536501591 1e-04 1e-06 -@value -8.172073868387086e-07 1e-04 1e-06 -@value -0.02806802638939627 1e-04 1e-06 -@value -0.005537900303758031 1e-04 1e-06 -@value 0 0.0001 1e-06 -Dictionary Key: alpha -@value 0.09973980264096334 1e-04 1e-06 -Dictionary Key: shapey -@value 1.559463012159858 1e-04 1e-06 -@value 1.231602807591228 1e-04 1e-06 -@value 1.803088011202189 1e-04 1e-06 -Dictionary Key: CMZ -Dictionary Key: actuator -@value -0.001714635571617953 1e-04 1e-06 -@value -0.0005710092451789862 1e-04 1e-06 -@value 0.0001053970922245933 1e-04 1e-06 -@value 0 0.0001 1e-06 -@value -0.002738231252915331 0.0001 1e-06 -@value 3.090059231618091e-07 0.0001 1e-06 -@value -0.005972163653488304 1e-04 1e-06 -@value 0.0002894111646713729 1e-04 1e-06 -@value -1.652421307341438e-05 1e-04 1e-06 -@value -1.640852649479966e-07 1e-04 1e-06 -@value 0.0004079649174387717 1e-04 1e-06 -@value 0.001743591514138321 1e-04 1e-06 -@value 0 0.0001 1e-06 -Dictionary Key: alpha -@value -0.00252751197470288 1e-04 1e-06 -Dictionary Key: shapey -@value 0.04277114768660325 1e-04 1e-06 -@value 0.3266475035683201 1e-04 1e-06 -@value 0.7983250993983276 1e-04 1e-06 -Dictionary Key: THRUST -Dictionary Key: actuator -@value 0.3141086102615986 1e-04 1e-06 -@value -0.003605129121397876 1e-04 1e-06 -@value 0.007310727357323632 1e-04 1e-06 -@value 0 0.0001 1e-06 -@value 0.356700099055085 0.0001 1e-06 -@value -5.536203717682042e-07 0.0001 1e-06 -@value -0.819670401731476 1e-04 1e-06 -@value 0.8428678211159779 1e-04 1e-06 -@value 0.003964124860367235 1e-04 1e-06 -@value 0 1e-04 1e-06 -@value -0.2740304202085708 1e-04 1e-06 -@value -0.3409006479776489 1e-04 1e-06 -@value 0 0.0001 1e-06 -Dictionary Key: alpha -@value 0 1e-04 1e-06 -Dictionary Key: shapey -@value -0.009188209263988334 1e-04 1e-06 -@value 0.0006339731860594 1e-04 1e-06 -@value 0.0007674441613869654 1e-04 1e-06 -Dictionary Key: VOL -Dictionary Key: actuator -@value -1.789350017581762 1e-04 1e-06 -@value 11.26830256393616 1e-04 1e-06 -@value 0.2116803123864702 1e-04 1e-06 -@value 0 0.0001 1e-06 -@value -2.160271468861342 0.0001 1e-06 -@value -0.000198398358891418 0.0001 1e-06 -@value -18.33919528265704 1e-04 1e-06 -@value -2.835167655956745 1e-04 1e-06 -@value 0.03030092859457912 1e-04 1e-06 -@value -7.666586571084363e-05 1e-04 1e-06 -@value -3.581283376190157 1e-04 1e-06 -@value -1.311124366909558 1e-04 1e-06 -@value 0 0.0001 1e-06 -Dictionary Key: alpha -@value 10.47559304035274 1e-04 1e-06 -Dictionary Key: shapey -@value 213.3053877790166 1e-04 1e-06 -@value 145.9822612662322 1e-04 1e-06 -@value 168.87748437004 1e-04 1e-06 -Dictionary Key: fail -@value 0 1e-04 1e-06 \ No newline at end of file +Dictionary Key: shape +@value 1.243384514756609 1e-08 1e-12 +Dictionary Key: twist +@value 0.0975429482398948 1e-08 1e-12 +Dictionary Key: LoD +Dictionary Key: shape +@value 62.66435123225894 1e-08 1e-12 +Dictionary Key: twist +@value 4.428296159540333 1e-08 1e-12 \ No newline at end of file diff --git a/tests/runRegTests_DASimpleFoam.py b/tests/runRegTests_DASimpleFoam.py new file mode 100755 index 00000000..e6b7dfd4 --- /dev/null +++ b/tests/runRegTests_DASimpleFoam.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python +""" +Run Python tests for optimization integration +""" + +from mpi4py import MPI +import os +import numpy as np +from testFuncs import * + +import openmdao.api as om +from mphys.multipoint import Multipoint +from dafoam.mphys import DAFoamBuilder, OptFuncs +from mphys.scenario_aerodynamic import ScenarioAerodynamic +from pygeo.mphys import OM_DVGEOCOMP + +gcomm = MPI.COMM_WORLD + +os.chdir("./reg_test_files-main/NACA0012") +if gcomm.rank == 0: + os.system("rm -rf 0 processor*") + os.system("cp -r 0.incompressible 0") + os.system("cp -r system.incompressible system") + os.system("cp -r constant/turbulenceProperties.sa constant/turbulenceProperties") + replace_text_in_file("system/fvSchemes", "meshWave;", "meshWaveFrozen;") + +# aero setup +U0 = 10.0 +p0 = 0.0 +A0 = 0.1 +twist0 = 3.0 +LRef = 1.0 +nuTilda0 = 4.5e-5 + +daOptions = { + "designSurfaces": ["wing"], + "solverName": "DASimpleFoam", + "primalMinResTol": 1.0e-12, + "primalMinResTolDiff": 1e4, + "primalBC": { + "U0": {"variable": "U", "patches": ["inout"], "value": [U0, 0.0, 0.0]}, + "p0": {"variable": "p", "patches": ["inout"], "value": [p0]}, + "nuTilda0": {"variable": "nuTilda", "patches": ["inout"], "value": [nuTilda0]}, + "useWallFunction": True, + "transport:nu": 1.5e-5, + }, + "function": { + "CD": { + "part1": { + "type": "force", + "source": "patchToFace", + "patches": ["wing"], + "directionMode": "fixedDirection", + "direction": [1.0, 0.0, 0.0], + "scale": 1.0 / (0.5 * U0 * U0 * A0), + "addToAdjoint": True, + } + }, + "CL": { + "part1": { + "type": "force", + "source": "patchToFace", + "patches": ["wing"], + "directionMode": "fixedDirection", + "direction": [0.0, 1.0, 0.0], + "scale": 1.0 / (0.5 * U0 * U0 * A0), + "addToAdjoint": True, + } + }, + }, + "adjEqnOption": { + "gmresRelTol": 1.0e-12, + "pcFillLevel": 1, + "jacMatReOrdering": "rcm", + "dynAdjustTol": False + }, + "normalizeStates": {"U": U0, "p": U0 * U0 / 2.0, "phi": 1.0, "nuTilda": 1e-3}, + "designVar": { + "twist": {"designVarType": "FFD"}, + "shape": {"designVarType": "FFD"}, + }, +} + +meshOptions = { + "gridFile": os.getcwd(), + "fileType": "OpenFOAM", + # point and normal for the symmetry plane + "symmetryPlanes": [[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]], [[0.0, 0.0, 0.1], [0.0, 0.0, 1.0]]], +} + + +class Top(Multipoint): + def setup(self): + dafoam_builder = DAFoamBuilder(daOptions, meshOptions, scenario="aerodynamic") + dafoam_builder.initialize(self.comm) + + ################################################################################ + # MPHY setup + ################################################################################ + + # ivc to keep the top level DVs + self.add_subsystem("dvs", om.IndepVarComp(), promotes=["*"]) + + # create the mesh and cruise scenario because we only have one analysis point + self.add_subsystem("mesh", dafoam_builder.get_mesh_coordinate_subsystem()) + + # add the geometry component, we dont need a builder because we do it here. + self.add_subsystem("geometry", OM_DVGEOCOMP(file="FFD/wingFFD.xyz", type="ffd")) + + self.mphys_add_scenario("cruise", ScenarioAerodynamic(aero_builder=dafoam_builder)) + + self.connect("mesh.x_aero0", "geometry.x_aero_in") + self.connect("geometry.x_aero0", "cruise.x_aero") + + self.add_subsystem("LoD", om.ExecComp("val=CL/CD")) + + def configure(self): + + self.cruise.aero_post.mphys_add_funcs() + + # create geometric DV setup + points = self.mesh.mphys_get_surface_mesh() + + # add pointset + self.geometry.nom_add_discipline_coords("aero", points) + + # geometry setup + + pts = self.geometry.DVGeo.getLocalIndex(0) + dir_y = np.array([0.0, 1.0, 0.0]) + shapes = [] + shapes.append({pts[2, 1, 0]: dir_y, pts[2, 1, 1]: dir_y}) + self.geometry.nom_addShapeFunctionDV(dvName="shape", shapes=shapes) + + self.geometry.nom_addRefAxis(name="wingAxis", xFraction=0.25, alignIndex="k") + + # Set up global design variables. We dont change the root twist + def twist(val, geo): + for i in range(2): + geo.rot_z["wingAxis"].coef[i] = -val[0] + + self.geometry.nom_addGlobalDV(dvName="twist", value=np.ones(1) * twist0, func=twist) + + # add the design variables to the dvs component's output + self.dvs.add_output("twist", val=np.ones(1) * twist0) + self.dvs.add_output("shape", val=np.zeros(1)) + # manually connect the dvs output to the geometry and cruise + self.connect("twist", "geometry.twist") + self.connect("shape", "geometry.shape") + + # define the design variables to the top level + self.add_design_var("twist", lower=-10.0, upper=10.0, scaler=1.0) + self.add_design_var("shape", lower=-10.0, upper=10.0, scaler=1.0) + + # add constraints and the objective + self.connect("cruise.aero_post.CD", "LoD.CD") + self.connect("cruise.aero_post.CL", "LoD.CL") + self.add_objective("LoD.val", scaler=1.0) + self.add_constraint("cruise.aero_post.CL", equals=0.3) + + +prob = om.Problem() +prob.model = Top() + +prob.setup(mode="rev") +om.n2(prob, show_browser=False, outfile="mphys_aero.html") + +optFuncs = OptFuncs(daOptions, prob) + +# verify the total derivatives against the finite-difference +prob.run_model() +results = prob.check_totals( + of=["LoD.val", "cruise.aero_post.CL"], wrt=["twist", "shape"], compact_print=True, step=1e-3, form="central", step_calc="abs" +) + +if gcomm.rank == 0: + funcDict = {} + funcDict["CD"] = prob.get_val("cruise.aero_post.CD") + funcDict["CL"] = prob.get_val("cruise.aero_post.CL") + derivDict = {} + derivDict["LoD"] = {} + derivDict["LoD"]["shape"] = results[("LoD.val", "shape")]["J_fwd"][0] + derivDict["LoD"]["twist"] = results[("LoD.val", "twist")]["J_fwd"][0] + derivDict["CL"] = {} + derivDict["CL"]["shape"] = results[("cruise.aero_post.CL", "shape")]["J_fwd"][0] + derivDict["CL"]["twist"] = results[("cruise.aero_post.CL", "twist")]["J_fwd"][0] + reg_write_dict(funcDict, 1e-10, 1e-12) + reg_write_dict(derivDict, 1e-8, 1e-12) diff --git a/tests/runTests_DASimpleFoam.py b/tests/runTests_DASimpleFoam.py deleted file mode 100755 index 8ec57dad..00000000 --- a/tests/runTests_DASimpleFoam.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/usr/bin/env python -""" -Run Python tests for DASimpleFoam -""" - -from mpi4py import MPI -from dafoam import PYDAFOAM, optFuncs -import sys -import os -from pygeo import * -from pyspline import * -from idwarp import * -from pyoptsparse import Optimization, OPT -import numpy as np -from testFuncs import * - -calcFDSens = 0 -if len(sys.argv) != 1: - if sys.argv[1] == "calcFDSens": - calcFDSens = 1 - -gcomm = MPI.COMM_WORLD - -os.chdir("./reg_test_files-main/NACA0012") - -if gcomm.rank == 0: - os.system("rm -rf 0 processor*") - os.system("cp -r 0.incompressible 0") - os.system("cp -r system.incompressible system") - os.system("cp -r constant/turbulenceProperties.sst constant/turbulenceProperties") - -U0 = 10.0 -p0 = 0.0 -k0 = 0.18 -omega0 = 1225.0 -A0 = 0.1 -alpha0 = 5.0 -LRef = 1.0 - -# test incompressible solvers -aeroOptions = { - "solverName": "DASimpleFoam", - "useAD": {"mode": "fd"}, - "designSurfaces": ["wing"], - "primalMinResTol": 1e-12, - "writeJacobians": ["all"], - "primalBC": { - "U0": {"variable": "U", "patches": ["inout"], "value": [U0, 0.0, 0.0]}, - "p0": {"variable": "p", "patches": ["inout"], "value": [p0]}, - "k0": {"variable": "k", "patches": ["inout"], "value": [k0]}, - "omega0": {"variable": "omega", "patches": ["inout"], "value": [omega0]}, - "useWallFunction": False, - "transport:nu": 1.5e-5, - }, - "fvSource": { - "disk1": { - "type": "actuatorDisk", - "source": "cylinderAnnulusSmooth", - "center": [-0.55, 0.0, 0.05], - "direction": [1.0, 0.0, 0.0], - "innerRadius": 0.01, - "outerRadius": 0.4, - "rotDir": "right", - "scale": 100.0, - "POD": 0.0, - "eps": 0.1, # eps should be of cell size - "expM": 1.0, - "expN": 0.5, - "adjustThrust": 0, - "targetThrust": 1.0, - }, - }, - "objFunc": { - "CD": { - "part1": { - "type": "force", - "source": "patchToFace", - "patches": ["wing"], - "directionMode": "parallelToFlow", - "alphaName": "alpha", - "scale": 1.0 / (0.5 * U0 * U0 * A0), - "addToAdjoint": True, - } - }, - "CL": { - "part1": { - "type": "force", - "source": "patchToFace", - "patches": ["wing"], - "directionMode": "normalToFlow", - "alphaName": "alpha", - "scale": 1.0 / (0.5 * U0 * U0 * A0), - "addToAdjoint": True, - } - }, - "CMZ": { - "part1": { - "type": "moment", - "source": "patchToFace", - "patches": ["wing"], - "axis": [0.0, 0.0, 1.0], - "center": [0.25, 0.0, 0.05], - "scale": 1.0 / (0.5 * U0 * U0 * A0 * LRef), - "addToAdjoint": True, - } - }, - "THRUST": { - "part1": { - "type": "variableVolSum", - "source": "boxToCell", - "min": [-50.0, -50.0, -50.0], - "max": [50.0, 50.0, 50.0], - "varName": "fvSource", - "varType": "vector", - "component": 0, - "isSquare": 0, - "divByTotalVol": 0, - "scale": 1.0, - "addToAdjoint": True, - }, - }, - "VOL": { - "part1": { - "type": "variableVolSum", - "source": "boxToCell", - "min": [-50.0, -50.0, -50.0], - "max": [50.0, 50.0, 50.0], - "varName": "p", - "varType": "scalar", - "component": 0, - "isSquare": 1, - "divByTotalVol": 0, - "scale": 1.0, - "addToAdjoint": True, - }, - }, - }, - "normalizeStates": {"U": U0, "p": U0 * U0 / 2.0, "k": k0, "omega": omega0, "phi": 1.0}, - "adjPartDerivFDStep": {"State": 1e-6, "FFD": 1e-3, "ACTD": 1.0e-3}, - "adjEqnOption": {"gmresRelTol": 1.0e-10, "gmresAbsTol": 1.0e-15, "pcFillLevel": 1, "jacMatReOrdering": "natural"}, - # Design variable setup - "designVar": { - "shapey": {"designVarType": "FFD"}, - "alpha": {"designVarType": "AOA", "patches": ["inout"], "flowAxis": "x", "normalAxis": "y"}, - "actuator": {"actuatorName": "disk1", "designVarType": "ACTD", "comps": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}, - }, -} - -# mesh warping parameters, users need to manually specify the symmetry plane -meshOptions = { - "gridFile": os.getcwd(), - "fileType": "OpenFOAM", - # point and normal for the symmetry plane - "symmetryPlanes": [[[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]], [[0.0, 0.0, 0.1], [0.0, 0.0, 1.0]]], -} - -# DVGeo -FFDFile = "./FFD/wingFFD.xyz" -DVGeo = DVGeometry(FFDFile) - -# nTwists is the number of FFD points in the spanwise direction -nTwists = DVGeo.addRefAxis("bodyAxis", xFraction=0.25, alignIndex="k") - - -def alpha(val, DASolver): - aoa = val[0] * np.pi / 180.0 - inletU = [float(U0 * np.cos(aoa)), float(U0 * np.sin(aoa)), 0] - DASolver.setOption("primalBC", {"U0": {"variable": "U", "patches": ["inout"], "value": inletU}}) - DASolver.updateDAOption() - - -def actuator(val, geo): - actX = float(val[0]) - actY = float(val[1]) - actZ = float(val[2]) - actDirx = float(val[3]) - actDiry = float(val[4]) - actDirz = float(val[5]) - actR1 = float(val[6]) - actR2 = float(val[7]) - actScale = float(val[8]) - actPOD = float(val[9]) - actExpM = float(val[10]) - actExpN = float(val[11]) - T = float(val[12]) - DASolver.setOption( - "fvSource", - { - "disk1": { - "type": "actuatorDisk", - "source": "cylinderAnnulusSmooth", - "center": [actX, actY, actZ], - "direction": [actDirx, actDiry, actDirz], - "innerRadius": actR1, - "outerRadius": actR2, - "rotDir": "right", - "scale": actScale, - "POD": actPOD, - "eps": 0.1, # eps should be of cell size - "expM": actExpM, - "expN": actExpN, - "adjustThrust": 0, - "targetThrust": T, - }, - }, - ) - DASolver.updateDAOption() - - -# select points -pts = DVGeo.getLocalIndex(0) -indexList = pts[1:4, 1, 0].flatten() -PS = geo_utils.PointSelect("list", indexList) -DVGeo.addLocalDV("shapey", lower=-1.0, upper=1.0, axis="y", scale=1.0, pointSelect=PS) -# actuator -DVGeo.addGlobalDV( - "actuator", - value=[-0.55, 0.0, 0.05, 1.0, 0.0, 0.0, 0.01, 0.4, 100.0, 0.0, 1.0, 0.5, 1.0], - func=actuator, - lower=-100.0, - upper=100.0, - scale=1.0, -) - -# DAFoam -DASolver = PYDAFOAM(options=aeroOptions, comm=gcomm) -DASolver.addInternalDV("alpha", [alpha0], alpha, lower=-10.0, upper=10.0, scale=1.0) -DASolver.setDVGeo(DVGeo) -mesh = USMesh(options=meshOptions, comm=gcomm) -DASolver.printFamilyList() -DASolver.setMesh(mesh) -# set evalFuncs -evalFuncs = [] -DASolver.setEvalFuncs(evalFuncs) - -# DVCon -DVCon = DVConstraints() -DVCon.setDVGeo(DVGeo) -[p0, v1, v2] = DASolver.getTriangulatedMeshSurface(groupName=DASolver.designSurfacesGroup) -surf = [p0, v1, v2] -DVCon.setSurface(surf) - -# optFuncs -optFuncs.DASolver = DASolver -optFuncs.DVGeo = DVGeo -optFuncs.DVCon = DVCon -optFuncs.evalFuncs = evalFuncs -optFuncs.gcomm = gcomm - -# Run -if calcFDSens == 1: - optFuncs.calcFDSens(objFun=optFuncs.calcObjFuncValues, fileName="sensFD.txt") -else: - DASolver.runColoring() - xDV = DVGeo.getValues() - iDV = DASolver.getInternalDVDict() - allDV = {**xDV, **iDV} - funcs = {} - funcs, fail = optFuncs.calcObjFuncValues(allDV) - # test getForces - forces = DASolver.getForces() - fNorm = np.linalg.norm(forces.flatten()) - fNormSum = gcomm.allreduce(fNorm, op=MPI.SUM) - funcs["forces"] = fNormSum - - funcsSens = {} - funcsSens, fail = optFuncs.calcObjFuncSens(allDV, funcs) - if gcomm.rank == 0: - reg_write_dict(funcs, 1e-8, 1e-10) - reg_write_dict(funcsSens, 1e-4, 1e-6)