diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..0d08e261 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/build-custom.yml b/.github/workflows/build-custom.yml index 2dc6d5fa..eec2d4ed 100644 --- a/.github/workflows/build-custom.yml +++ b/.github/workflows/build-custom.yml @@ -8,6 +8,7 @@ on: required: true type: choice options: + - ubuntu-22.04 - ubuntu-20.04 - ubuntu-18.04 refAdapter: @@ -19,6 +20,8 @@ on: required: true type: choice options: + - OpenFOAMv2312 + - OpenFOAMv2306 - OpenFOAMv2212 - OpenFOAMv2206 - OpenFOAMv2112 @@ -34,7 +37,7 @@ on: - OpenFOAM5 versionpreCICE: description: 'Version of preCICE to build with' - default: '2.3.0' + default: 'v3.0.0' required: true runTutorialHeatedPlate: description: Run tutorial flow-over-heated-plate @@ -72,96 +75,104 @@ jobs: echo "Run tutorial partitioned-pipe: ${{ github.event.inputs.runTutorialPartitionedPipe }}" echo "Tutorials branch: ${{ github.event.inputs.branchTutorials }}" - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.refAdapter }} + - name: Install preCICE (no cache) + uses: precice/setup-precice-action@main + with: + precice-version: ${{ github.event.inputs.versionpreCICE }} - name: Install OpenFOAM (no cache) id: installOpenFOAM run: | case "${{ github.event.inputs.versionOpenFOAM }}" in + OpenFOAMv2312) + wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash + sudo apt-get install openfoam2312-dev + echo "{openfoam_exec}={/usr/bin/openfoam2312}" >> $GITHUB_OUTPUT;; + OpenFOAMv2306) + wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash + sudo apt-get install openfoam2306-dev + echo "{openfoam_exec}={/usr/bin/openfoam2306}" >> $GITHUB_OUTPUT;; OpenFOAMv2212) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2212-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2212";; + echo "{openfoam_exec}={/usr/bin/openfoam2212}" >> $GITHUB_OUTPUT;; OpenFOAMv2206) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2206-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2206";; + echo "{openfoam_exec}={/usr/bin/openfoam2206}" >> $GITHUB_OUTPUT;; OpenFOAMv2112) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2112-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2112";; + echo "{openfoam_exec}={/usr/bin/openfoam2112}" >> $GITHUB_OUTPUT;; OpenFOAMv2106) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2106-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2106";; + echo "{openfoam_exec}={/usr/bin/openfoam2106}" >> $GITHUB_OUTPUT;; OpenFOAMv2012) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2012-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2012";; + echo "{openfoam_exec}={/usr/bin/openfoam2012}" >> $GITHUB_OUTPUT;; OpenFOAMv2006) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam2006-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam2006";; + echo "{openfoam_exec}={/usr/bin/openfoam2006}" >> $GITHUB_OUTPUT;; OpenFOAMv1912) wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash sudo apt-get install openfoam1912-dev - echo "::set-output name=openfoam_exec::/usr/bin/openfoam1912";; + echo "{openfoam_exec}={/usr/bin/openfoam1912}" >> $GITHUB_OUTPUT;; OpenFOAM10) sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam10 - echo "::set-output name=openfoam_exec::. /opt/openfoam10/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam10/etc/bashrc &&}" >> $GITHUB_OUTPUT;; OpenFOAM9) sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam9 - echo "::set-output name=openfoam_exec::. /opt/openfoam9/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam9/etc/bashrc &&}" >> $GITHUB_OUTPUT;; OpenFOAM8) sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam8 - echo "::set-output name=openfoam_exec::. /opt/openfoam8/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam8/etc/bashrc &&}" >> $GITHUB_OUTPUT;; OpenFOAM7) sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam7 - echo "::set-output name=openfoam_exec::. /opt/openfoam7/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam7/etc/bashrc &&}" >> $GITHUB_OUTPUT;; OpenFOAM6) echo "OpenFOAM 6 is only available on Ubuntu 18.04 or older." sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam6 - echo "::set-output name=openfoam_exec::. /opt/openfoam6/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam6/etc/bashrc &&}" >> $GITHUB_OUTPUT;; OpenFOAM5) echo "OpenFOAM 5 is only available on Ubuntu 18.04 or older." sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" sudo add-apt-repository http://dl.openfoam.org/ubuntu sudo apt-get update sudo apt-get -y install openfoam5 - echo "::set-output name=openfoam_exec::. /opt/openfoam5/etc/bashrc &&";; + echo "{openfoam_exec}={. /opt/openfoam5/etc/bashrc &&}" >> $GITHUB_OUTPUT;; *) echo "I cannot find ${{ github.event.inputs.refAdapter }} in my known options." exit 1;; esac - - name: Install preCICE (no cache) + - name: Sanity check run: | - if [ "${{ github.event.inputs.virtualEnvironment }}" == "ubuntu-20.04" ] - then - wget "https://github.com/precice/precice/releases/download/v${{ github.event.inputs.versionpreCICE }}/libprecice2_${{ github.event.inputs.versionpreCICE }}_focal.deb" - sudo apt install "./libprecice2_${{ github.event.inputs.versionpreCICE }}_focal.deb" - elif [ "${{ github.event.inputs.virtualEnvironment }}" == "ubuntu-18.04" ] - then - wget "https://github.com/precice/precice/releases/download/v${{ github.event.inputs.versionpreCICE }}/libprecice2_${{ github.event.inputs.versionpreCICE }}_bionic.deb" - sudo apt install "./libprecice2_${{ github.event.inputs.versionpreCICE }}_bionic.deb" - fi + ls /usr/bin/openfoam* || echo "No /usr/bin/openfoam* directories." + ls /opt/openfoam* || echo "No /opt/openfoam* directories." + echo "GitHub Actions step output openfoam_exec:" + echo ${{steps.installOpenFOAM.outputs.openfoam_exec}} - name: Build OpenFOAM-preCICE adapter run: | + echo "OpenFOAM environment: ${{steps.installOpenFOAM.outputs.openfoam_exec}}" ${{steps.installOpenFOAM.outputs.openfoam_exec}} ./Allwmake - name: Get tutorials run: | @@ -210,7 +221,7 @@ jobs: wait $PIDfluid fi - name: Archive logs - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: logs path: | @@ -224,7 +235,7 @@ jobs: tutorials/partitioned-pipe/fluid1-openfoam-pimplefoam/fluid1-openfoam-pimplefoam.log tutorials/partitioned-pipe/fluid2-openfoam-pimplefoam/fluid2-openfoam-pimplefoam.log - name: Archive case files - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: case-files path: | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fd80140a..5b6b5927 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build with OpenFOAM v2212 +name: Build with OpenFOAM v2312 on: push: branches-ignore: @@ -20,23 +20,28 @@ on: - 'README.md' jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 + container: precice/precice:nightly steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 + - name: Install action dependencies + run: | + apt-get update -qq + apt-get install -qq sudo wget - name: Setup caches - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-id with: path: ${{ runner.temp }}/cache-directory key: ${{ runner.os }}-cache-dependencies-v1.0 - - name: Install dependencies (considering cache) + - name: Install OpenFOAM (considering cache) uses: airvzxf/cache-anything-new-action@v1.0.1 with: - script: 'install-dependencies.sh' + script: 'install-openfoam.sh' is_cached: ${{ steps.cache-id.outputs.cache-hit }} cache: ${{ runner.temp }}/cache-directory snapshot: '/' exclude: '/boot /data /dev /mnt /proc /run /sys' - name: Build OpenFOAM-preCICE adapter - run: /usr/bin/openfoam2212 ./Allwmake + run: /usr/bin/openfoam2312 ./Allwmake diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml index 1ade288c..c765840e 100644 --- a/.github/workflows/check-format.yml +++ b/.github/workflows/check-format.yml @@ -5,7 +5,7 @@ jobs: name: Check formatting (clang-format) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run clang-format style check for C/C++ programs. uses: jidicula/clang-format-action@main with: diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml deleted file mode 100644 index f7e0ce61..00000000 --- a/.github/workflows/check-links.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Check links (manual) -on: workflow_dispatch -jobs: - check_links: - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v2 - - name: Check links in markdown files (markdown-link-check) - uses: gaurav-nelson/github-action-markdown-link-check@v1 - with: - use-quiet-mode: 'yes' - use-verbose-mode: 'no' - config-file: '.markdown-link-check-config.json' diff --git a/.github/workflows/check-markdown.yml b/.github/workflows/check-markdown.yml deleted file mode 100644 index 63a0df9a..00000000 --- a/.github/workflows/check-markdown.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Lint docs -on: [push, pull_request] -jobs: - check_md: - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v2 - - name: Lint markdown files (markdownlint) - uses: articulate/actions-markdownlint@v1 - with: - config: .markdownlint.json - files: '.' - ignore: changelog-entries diff --git a/.github/workflows/check-shell.yml b/.github/workflows/check-shell.yml index f4400ed0..dd5474f8 100644 --- a/.github/workflows/check-shell.yml +++ b/.github/workflows/check-shell.yml @@ -5,6 +5,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Lint shell scripts (shellcheck) uses: ludeeus/action-shellcheck@master diff --git a/.github/workflows/install-dependencies.sh b/.github/workflows/install-dependencies.sh deleted file mode 100755 index b670d65c..00000000 --- a/.github/workflows/install-dependencies.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -e - -# Install OpenFOAM v2212 -wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash -sudo apt-get install openfoam2212-dev - -# Install preCICE v2.5.0 -wget https://github.com/precice/precice/releases/download/v2.5.0/libprecice2_2.5.0_focal.deb -sudo apt install ./libprecice2_2.5.0_focal.deb diff --git a/.github/workflows/install-openfoam.sh b/.github/workflows/install-openfoam.sh new file mode 100755 index 00000000..3b132427 --- /dev/null +++ b/.github/workflows/install-openfoam.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +# Install OpenFOAM v2312 +wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash +sudo apt-get update -y +sudo apt-get install -y openfoam2312-dev diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..f87390de --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,31 @@ +name: Pre-commit hook checks +on: + push: + branches: + - main + - develop + pull_request: + branches: + - "*" + +jobs: + formatting: + runs-on: ubuntu-latest + steps: + - name: Checkout preCICE + uses: actions/checkout@v4 + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + check-latest: true + - name: Install pre-commit + run: pip install pre-commit + - name: Run checks + run: pre-commit run -a -v + - name: Git status + if: always() + run: git status + - name: Full diff + if: always() + run: git diff diff --git a/.github/workflows/system-tests.yaml b/.github/workflows/system-tests.yaml new file mode 100644 index 00000000..e6e6145f --- /dev/null +++ b/.github/workflows/system-tests.yaml @@ -0,0 +1,29 @@ +name: System tests + +on: + pull_request: + types: [labeled] + +jobs: + gather-refs: + if: ${{ github.event.label.name == 'trigger-system-tests' }} + runs-on: ubuntu-latest + outputs: + reftutorials: ${{ steps.reftutorials.outputs.shorthash }} + steps: + - id: reftutorials + uses: nmbgeek/github-action-get-latest-commit@main + with: + owner: precice + repo: tutorials + branch: develop + + run-system-tests: + if: ${{ github.event.label.name == 'trigger-system-tests' }} + needs: gather-refs + uses: precice/tutorials/.github/workflows/run_testsuite_workflow.yml@develop + with: + suites: openfoam_adapter_pr + build_args: TUTORIALS_REF:${{ needs.gather-refs.outputs.reftutorials }},PRECICE_REF:v3.0.0,OPENFOAM_EXECUTABLE:openfoam2312,OPENFOAM_ADAPTER_REF:${{ github.event.pull_request.head.sha }} + systests_branch: develop + loglevel: "DEBUG" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f3554f66 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: +# Official repo for default hooks +- repo: https://github.com/precice/precice-pre-commit-hooks + rev: 'v3.3' + hooks: + - id: format-precice-config + - id: check-image-prefix + args: [ --prefix=docs-adapter-openfoam- ] +- repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.30.0 + hooks: + - id: markdownlint + files: "^docs/.*.md" + - id: markdownlint-fix + files: "^docs/.*.md" +- repo: https://github.com/koalaman/shellcheck-precommit + rev: v0.10.0 + hooks: + - id: shellcheck + args: [ --external-sources, --exclude=SC1091 ] diff --git a/Adapter.C b/Adapter.C index c4c3e988..203a4f15 100644 --- a/Adapter.C +++ b/Adapter.C @@ -10,7 +10,7 @@ preciceAdapter::Adapter::Adapter(const Time& runTime, const fvMesh& mesh) : runTime_(runTime), mesh_(mesh) { - adapterInfo("Loaded the OpenFOAM-preCICE adapter - v1.2.3.", "info"); + adapterInfo("Loaded the OpenFOAM-preCICE adapter - v1.3.0.", "info"); return; } @@ -101,9 +101,9 @@ bool preciceAdapter::Adapter::configFileRead() // By default, assume that no mesh connectivity is required (i.e. no nearest-projection mapping) interfaceConfig.meshConnectivity = interfaceDict.lookupOrDefault("connectivity", false); // Mesh connectivity only makes sense in case of faceNodes, check and raise a warning otherwise - if (interfaceConfig.meshConnectivity && interfaceConfig.locationsType == "faceCenters") + if (interfaceConfig.meshConnectivity && (interfaceConfig.locationsType == "faceCenters" || interfaceConfig.locationsType == "volumeCenters" || interfaceConfig.locationsType == "volumeCentres")) { - DEBUG(adapterInfo("Mesh connectivity is not supported for faceCenters. \n" + DEBUG(adapterInfo("Mesh connectivity is not supported for faceCenters or volumeCenters. \n" "Please configure the desired interface with the locationsType faceNodes. \n" "Have a look in the adapter documentation for detailed information.", "warning")); @@ -119,6 +119,24 @@ bool preciceAdapter::Adapter::configFileRead() DEBUG(adapterInfo(" - " + patch)); } + DEBUG(adapterInfo(" cellSets : ")); + auto cellSets = interfaceDict.lookupOrDefault("cellSets", wordList()); + + for (auto cellSet : cellSets) + { + interfaceConfig.cellSetNames.push_back(cellSet); + DEBUG(adapterInfo(" - " + cellSet)); + } + + if (!interfaceConfig.cellSetNames.empty() && !(interfaceConfig.locationsType == "volumeCenters" || interfaceConfig.locationsType == "volumeCentres")) + { + adapterInfo("Cell sets are not supported for locationType != volumeCenters. \n" + "Please configure the desired interface with the locationsType volumeCenters. \n" + "Have a look in the adapter documentation for detailed information.", + "warning"); + return false; + } + DEBUG(adapterInfo(" writeData : ")); auto writeData = interfaceDict.get("writeData"); for (auto writeDatum : writeData) @@ -246,7 +264,7 @@ void preciceAdapter::Adapter::configure() DEBUG(adapterInfo("Creating the preCICE solver interface...")); DEBUG(adapterInfo(" Number of processes: " + std::to_string(Pstream::nProcs()))); DEBUG(adapterInfo(" MPI rank: " + std::to_string(Pstream::myProcNo()))); - precice_ = new precice::SolverInterface(participantName_, preciceConfigFilename_, Pstream::myProcNo(), Pstream::nProcs()); + precice_ = new precice::Participant(participantName_, preciceConfigFilename_, Pstream::myProcNo(), Pstream::nProcs()); DEBUG(adapterInfo(" preCICE solver interface was created.")); ACCUMULATE_TIMER(timeInPreciceConstruct_); @@ -260,7 +278,7 @@ void preciceAdapter::Adapter::configure() std::string nameCellDisplacement = FSIenabled_ ? FSI_->getCellDisplacementFieldName() : "default"; bool restartFromDeformed = FSIenabled_ ? FSI_->isRestartingFromDeformed() : false; - Interface* interface = new Interface(*precice_, mesh_, interfacesConfig_.at(i).meshName, interfacesConfig_.at(i).locationsType, interfacesConfig_.at(i).patchNames, interfacesConfig_.at(i).meshConnectivity, restartFromDeformed, namePointDisplacement, nameCellDisplacement); + Interface* interface = new Interface(*precice_, mesh_, interfacesConfig_.at(i).meshName, interfacesConfig_.at(i).locationsType, interfacesConfig_.at(i).patchNames, interfacesConfig_.at(i).cellSetNames, interfacesConfig_.at(i).meshConnectivity, restartFromDeformed, namePointDisplacement, nameCellDisplacement); interfaces_.push_back(interface); DEBUG(adapterInfo("Interface created on mesh " + interfacesConfig_.at(i).meshName)); @@ -345,12 +363,9 @@ void preciceAdapter::Adapter::configure() // Initialize preCICE and exchange the first coupling data initialize(); - // Read the received coupling data - readCouplingData(); - // If checkpointing is required, specify the checkpointed fields // and write the first checkpoint - if (isWriteCheckpointRequired()) + if (requiresWritingCheckpoint()) { checkpointing_ = true; @@ -359,13 +374,12 @@ void preciceAdapter::Adapter::configure() // Write checkpoint (for the first iteration) writeCheckpoint(); - fulfilledWriteCheckpoint(); } // Adjust the timestep for the first iteration, if it is fixed if (!adjustableTimestep_) { - adjustSolverTimeStep(); + adjustSolverTimeStepAndReadData(); } // If the solver tries to end before the coupling is complete, @@ -421,23 +435,15 @@ void preciceAdapter::Adapter::execute() advance(); // Read checkpoint if required - if (isReadCheckpointRequired()) + if (requiresReadingCheckpoint()) { readCheckpoint(); - fulfilledReadCheckpoint(); - } - - // Adjust the timestep, if it is fixed - if (!adjustableTimestep_) - { - adjustSolverTimeStep(); } // Write checkpoint if required - if (isWriteCheckpointRequired()) + if (requiresWritingCheckpoint()) { writeCheckpoint(); - fulfilledWriteCheckpoint(); } // As soon as OpenFOAM writes the results, it will not try to write again @@ -461,8 +467,11 @@ void preciceAdapter::Adapter::execute() } ACCUMULATE_TIMER(timeInWriteResults_); - // Read the received coupling data from the buffer - readCouplingData(); + // Adjust the timestep, if it is fixed + if (!adjustableTimestep_) + { + adjustSolverTimeStepAndReadData(); + } // If the coupling is not going to continue, tear down everything // and stop the simulation. @@ -491,21 +500,22 @@ void preciceAdapter::Adapter::execute() return; } + void preciceAdapter::Adapter::adjustTimeStep() { - adjustSolverTimeStep(); + adjustSolverTimeStepAndReadData(); return; } -void preciceAdapter::Adapter::readCouplingData() +void preciceAdapter::Adapter::readCouplingData(double relativeReadTime) { SETUP_TIMER(); DEBUG(adapterInfo("Reading coupling data...")); for (uint i = 0; i < interfaces_.size(); i++) { - interfaces_.at(i)->readCouplingData(); + interfaces_.at(i)->readCouplingData(relativeReadTime); } ACCUMULATE_TIMER(timeInRead_); @@ -532,21 +542,14 @@ void preciceAdapter::Adapter::initialize() { DEBUG(adapterInfo("Initializing the preCICE solver interface...")); SETUP_TIMER(); - timestepPrecice_ = precice_->initialize(); - ACCUMULATE_TIMER(timeInInitialize_); - - preciceInitialized_ = true; - if (precice_->isActionRequired(precice::constants::actionWriteInitialData())) - { + if (precice_->requiresInitialData()) writeCouplingData(); - precice_->markActionFulfilled(precice::constants::actionWriteInitialData()); - } DEBUG(adapterInfo("Initializing preCICE data...")); - REUSE_TIMER(); - precice_->initializeData(); - ACCUMULATE_TIMER(timeInInitializeData_); + precice_->initialize(); + preciceInitialized_ = true; + ACCUMULATE_TIMER(timeInInitialize_); adapterInfo("preCICE was configured and initialized", "info"); @@ -582,13 +585,13 @@ void preciceAdapter::Adapter::advance() DEBUG(adapterInfo("Advancing preCICE...")); SETUP_TIMER(); - timestepPrecice_ = precice_->advance(timestepSolver_); + precice_->advance(timestepSolver_); ACCUMULATE_TIMER(timeInAdvance_); return; } -void preciceAdapter::Adapter::adjustSolverTimeStep() +void preciceAdapter::Adapter::adjustSolverTimeStepAndReadData() { DEBUG(adapterInfo("Adjusting the solver's timestep...")); @@ -646,8 +649,8 @@ void preciceAdapter::Adapter::adjustSolverTimeStep() If the solver tries to use a bigger timestep, then it needs to use the same timestep as the one determined by preCICE. */ - - if (timestepSolverDetermined < timestepPrecice_) + double tolerance = 1e-14; + if (precice_->getMaxTimeStepSize() - timestepSolverDetermined > tolerance) { // Add a bool 'subCycling = true' which is checked in the storeMeshPoints() function. adapterInfo( @@ -663,20 +666,24 @@ void preciceAdapter::Adapter::adjustSolverTimeStep() "warning"); } } - else if (timestepSolverDetermined > timestepPrecice_) + else if (timestepSolverDetermined - precice_->getMaxTimeStepSize() > tolerance) { - adapterInfo( - "The solver's timestep cannot be larger than the coupling timestep." - " Adjusting from " - + std::to_string(timestepSolverDetermined) + " to " + std::to_string(timestepPrecice_), - "warning"); - timestepSolver_ = timestepPrecice_; + // In the last time-step, we adjust to dt = 0, but we don't need to trigger the warning here + if (precice_->isCouplingOngoing()) + { + adapterInfo( + "The solver's timestep cannot be larger than the coupling timestep." + " Adjusting from " + + std::to_string(timestepSolverDetermined) + " to " + std::to_string(precice_->getMaxTimeStepSize()), + "warning"); + } + timestepSolver_ = precice_->getMaxTimeStepSize(); } else { DEBUG(adapterInfo("The solver's timestep is the same as the " "coupling timestep.")); - timestepSolver_ = timestepPrecice_; + timestepSolver_ = precice_->getMaxTimeStepSize(); } // Update the solver's timestep (but don't trigger the adjustDeltaT(), @@ -684,6 +691,12 @@ void preciceAdapter::Adapter::adjustSolverTimeStep() // TODO: Keep this in mind if any relevant problem appears. const_cast(runTime_).setDeltaT(timestepSolver_, false); + DEBUG(adapterInfo("Reading coupling data associated to the calculated time-step size...")); + + // Read the received coupling data from the buffer + // Fits to an implicit Euler + readCouplingData(runTime_.deltaT().value()); + return; } @@ -708,29 +721,16 @@ bool preciceAdapter::Adapter::isCouplingTimeWindowComplete() return precice_->isTimeWindowComplete(); } -bool preciceAdapter::Adapter::isReadCheckpointRequired() +bool preciceAdapter::Adapter::requiresReadingCheckpoint() { - return precice_->isActionRequired(precice::constants::actionReadIterationCheckpoint()); + return precice_->requiresReadingCheckpoint(); } -bool preciceAdapter::Adapter::isWriteCheckpointRequired() +bool preciceAdapter::Adapter::requiresWritingCheckpoint() { - return precice_->isActionRequired(precice::constants::actionWriteIterationCheckpoint()); + return precice_->requiresWritingCheckpoint(); } -void preciceAdapter::Adapter::fulfilledReadCheckpoint() -{ - precice_->markActionFulfilled(precice::constants::actionReadIterationCheckpoint()); - - return; -} - -void preciceAdapter::Adapter::fulfilledWriteCheckpoint() -{ - precice_->markActionFulfilled(precice::constants::actionWriteIterationCheckpoint()); - - return; -} void preciceAdapter::Adapter::storeCheckpointTime() { @@ -1660,13 +1660,12 @@ preciceAdapter::Adapter::~Adapter() Info << " (I) writing checkpoints: " << timeInCheckpointingWrite_.str() << nl; Info << " (I) reading checkpoints: " << timeInCheckpointingRead_.str() << nl; Info << " (I) writing OpenFOAM results: " << timeInWriteResults_.str() << " (at the end of converged time windows)" << nl << nl; - Info << "Time exclusively in preCICE: " << (timeInInitialize_ + timeInInitializeData_ + timeInAdvance_ + timeInFinalize_).str() << nl; + Info << "Time exclusively in preCICE: " << (timeInInitialize_ + timeInAdvance_ + timeInFinalize_).str() << nl; Info << " (S) initialize(): " << timeInInitialize_.str() << nl; - Info << " (S) initializeData(): " << timeInInitializeData_.str() << nl; Info << " (I) advance(): " << timeInAdvance_.str() << nl; Info << " (I) finalize(): " << timeInFinalize_.str() << nl; Info << " These times include time waiting for other participants." << nl; - Info << " See also precice--events-summary.log." << nl; + Info << " See also precice-profiling on the website https://precice.org/tooling-performance-analysis.html." << nl; Info << "-------------------------------------------------------------------------------------" << nl;) return; diff --git a/Adapter.H b/Adapter.H index f94fd9c5..2e9cd606 100644 --- a/Adapter.H +++ b/Adapter.H @@ -22,7 +22,7 @@ #include "fvMesh.H" // preCICE Solver Interface -#include "precice/SolverInterface.hpp" +#include namespace preciceAdapter { @@ -41,6 +41,7 @@ private: std::string locationsType; bool meshConnectivity; std::vector patchNames; + std::vector cellSetNames; std::vector writeData; std::vector readData; }; @@ -54,7 +55,6 @@ private: clockValue timeInPreciceConstruct_; clockValue timeInMeshSetup_; clockValue timeInInitialize_; - clockValue timeInInitializeData_; clockValue timeInCheckpointingSetup_; clockValue timeInWrite_; clockValue timeInAdvance_; @@ -106,7 +106,7 @@ private: std::vector interfaces_; //- preCICE solver interface - precice::SolverInterface* precice_ = NULL; + precice::Participant* precice_ = nullptr; //- preCICE solver interface initialized bool preciceInitialized_ = false; @@ -124,9 +124,6 @@ private: // Timesteps - //- Timestep dictated by preCICE - double timestepPrecice_; - //- Timestep used by the solver double timestepSolver_; @@ -265,13 +262,14 @@ private: void advance(); //- Read the coupling data at each interface - void readCouplingData(); + void readCouplingData(double relativeReadTime); //- Write the coupling data at each interface void writeCouplingData(); //- Adjust the timestep of the solver according to preCICE - void adjustSolverTimeStep(); + // and read data associated to the calculated time step length + void adjustSolverTimeStepAndReadData(); //- Determine if the coupling is still happening bool isCouplingOngoing(); @@ -280,16 +278,10 @@ private: bool isCouplingTimeWindowComplete(); //- Determine if a checkpoint must be read - bool isReadCheckpointRequired(); + bool requiresReadingCheckpoint(); //- Determine if a checkpoint must be written - bool isWriteCheckpointRequired(); - - //- Tell preCICE that the checkpoint has been read - void fulfilledReadCheckpoint(); - - //- Tell preCICE that the checkpoint has been written - void fulfilledWriteCheckpoint(); + bool requiresWritingCheckpoint(); // Methods for checkpointing diff --git a/Allwmake b/Allwmake index 371c0cb4..d74d9fcd 100755 --- a/Allwmake +++ b/Allwmake @@ -6,11 +6,11 @@ set -e -u # Optional: Preprocessor flags # "-DADAPTER_DEBUG_MODE" enables debug messages # "-DADAPTER_ENABLE_TIMINGS" enables time measurements -ADAPTER_PREP_FLAGS="" +ADAPTER_PREP_FLAGS="${ADAPTER_PREP_FLAGS:-}" # Build command and options # In order to compile with multiple threads, set the environment variable WM_NCOMPPROCS, -# e.g., add "export WM_NCOMP_PROCS=4" to your ~/.bashrc +# e.g., add "export WM_NCOMPPROCS=4" to your ~/.bashrc # Make sure that these options are supported by your OpenFOAM version. adapter_build_command(){ wmake libso diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fe99340..264c5c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,36 @@ Read more details in the issue [#52: Releases and versioning](https://github.com +## [v1.3.0] 2024-03-20 + +### Added + +- Added a locationType for volume coupling and implemented the respective functionality (over all internal fields) for Pressure and Velocity (FF) and Temperature (FF) [#255](https://github.com/precice/openfoam-adapter/pull/255). +- Added volume coupling over one or multiple domain regions specified by OpenFOAM cellSets (for Pressure and Velocity (FF) and Temperature (FF))[#270](https://github.com/precice/openfoam-adapter/pull/270). +- Added phase variable and flux coupling for interFOAM in the FF module [#308](https://github.com/precice/openfoam-adapter/pull/308). +- Added custom inletOutlet boundary conditions for pressure and velocity to the FF module [#281](https://github.com/precice/openfoam-adapter/pull/281). +- Added temperature and temperature gradient as coupling data to the FF module [#281](https://github.com/precice/openfoam-adapter/pull/281). +- Added option to write velocity that is corrected by the face flux `phi` [#281](https://github.com/precice/openfoam-adapter/pull/281). +- Added a pre-commit hook to check formatting and linting of various aspects [#321](https://github.com/precice/openfoam-adapter/pull/321). +- Added a workflow for triggering system regression tests [#309](https://github.com/precice/openfoam-adapter/pull/309). +- Added citing guidelines, referring to the [new reference article at the OpenFOAM Journal](https://doi.org/10.51560/ofj.v3.88). [#287](https://github.com/precice/openfoam-adapter/pull/287) + +### Changed + +- Changed the preCICE dependency version to v3. The adapter is not compatible with v2 anymore. [#285](https://github.com/precice/openfoam-adapter/pull/285). +- Changed the default OpenFOAM version to v2312 in the documentation and CI. [#325](https://github.com/precice/openfoam-adapter/pull/325). +- Changed the way mesh connectivity (face triangles) are provided to preCICE, adapting to preCICE v3 [#297](https://github.com/precice/openfoam-adapter/pull/297). +- Renamed the `adjustSolverTimeStep()` method to `adjustSolverTimeStepAndReadData()`, changing the behavior to always read data at the determined time step size [#298](https://github.com/precice/openfoam-adapter/pull/298). +- Changed the build CI workflow to use the setup-precice-action to install preCICE [#299](https://github.com/precice/openfoam-adapter/pull/299). +- Improved building time by grouping together compilation units of each module [#301](https://github.com/precice/openfoam-adapter/pull/301). + ## [v1.2.3] 2023-06-14 ### Fixed - Fixed incorrect reading and writing of the FSI-related data buffers, if multiple patches are combined in an interface mesh [commit 846affd](https://github.com/precice/openfoam-adapter/commit/846affdd00ea8024cee98f34d8ad4205fdc83c5f). -## [v1.2.2] 2022-01-03 +## [v1.2.2] 2023-01-03 ### Changed diff --git a/CHT/HeatFlux.C b/CHT/HeatFlux.C index 27dcfa41..7c63e290 100644 --- a/CHT/HeatFlux.C +++ b/CHT/HeatFlux.C @@ -18,7 +18,7 @@ preciceAdapter::CHT::HeatFlux::HeatFlux( dataType_ = scalar; } -void preciceAdapter::CHT::HeatFlux::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::CHT::HeatFlux::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; @@ -68,6 +68,7 @@ void preciceAdapter::CHT::HeatFlux::write(double* buffer, bool meshConnectivity, } } } + return bufferIndex; } void preciceAdapter::CHT::HeatFlux::read(double* buffer, const unsigned int dim) @@ -111,7 +112,7 @@ bool preciceAdapter::CHT::HeatFlux::isLocationTypeSupported(const bool meshConne // always return true and offload the handling to the user. if (meshConnectivity) { - return true; + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::faceNodes); // we currently do not support meshConnectivity for volumeCenters } else { diff --git a/CHT/HeatFlux.H b/CHT/HeatFlux.H index ea21eac7..c3c4aa2e 100644 --- a/CHT/HeatFlux.H +++ b/CHT/HeatFlux.H @@ -33,7 +33,7 @@ public: //- Compute heat flux values from the temperature field // and write them into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read heat flux values from the buffer and assign them to // the gradient of the temperature field diff --git a/CHT/HeatTransferCoefficient.C b/CHT/HeatTransferCoefficient.C index 8da03c09..68778280 100644 --- a/CHT/HeatTransferCoefficient.C +++ b/CHT/HeatTransferCoefficient.C @@ -20,7 +20,7 @@ preciceAdapter::CHT::HeatTransferCoefficient::HeatTransferCoefficient( } -void preciceAdapter::CHT::HeatTransferCoefficient::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::CHT::HeatTransferCoefficient::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; @@ -69,6 +69,7 @@ void preciceAdapter::CHT::HeatTransferCoefficient::write(double* buffer, bool me } } } + return bufferIndex; } @@ -124,7 +125,7 @@ bool preciceAdapter::CHT::HeatTransferCoefficient::isLocationTypeSupported(const // always return true and offload the handling to the user. if (meshConnectivity) { - return true; + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::faceNodes); // we currently do not support meshConnectivity for volumeCenters } else { diff --git a/CHT/HeatTransferCoefficient.H b/CHT/HeatTransferCoefficient.H index c09edd00..bc0b887e 100644 --- a/CHT/HeatTransferCoefficient.H +++ b/CHT/HeatTransferCoefficient.H @@ -35,7 +35,7 @@ public: const std::string nameT); //- Write the heat transfer coefficient values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the heat transfer coefficient values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/CHT/ModuleCHT.C b/CHT/ModuleCHT.C new file mode 100644 index 00000000..2387b077 --- /dev/null +++ b/CHT/ModuleCHT.C @@ -0,0 +1,7 @@ +// Central inlude file to reduce the number of build targets and build time +#include "Temperature.C" +#include "KappaEffective.C" +#include "HeatFlux.C" +#include "HeatTransferCoefficient.C" +#include "SinkTemperature.C" +#include "CHT.C" diff --git a/CHT/SinkTemperature.C b/CHT/SinkTemperature.C index f373d650..9ed18244 100644 --- a/CHT/SinkTemperature.C +++ b/CHT/SinkTemperature.C @@ -14,7 +14,7 @@ preciceAdapter::CHT::SinkTemperature::SinkTemperature( dataType_ = scalar; } -void preciceAdapter::CHT::SinkTemperature::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::CHT::SinkTemperature::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; @@ -63,6 +63,7 @@ void preciceAdapter::CHT::SinkTemperature::write(double* buffer, bool meshConnec // Clear the temporary internal field object patchInternalFieldTmp.clear(); } + return bufferIndex; } void preciceAdapter::CHT::SinkTemperature::read(double* buffer, const unsigned int dim) @@ -101,7 +102,7 @@ bool preciceAdapter::CHT::SinkTemperature::isLocationTypeSupported(const bool me // always return true and offload the handling to the user. if (meshConnectivity) { - return true; + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::faceNodes); // we currently do not support meshConnectivity for volumeCenters } else { diff --git a/CHT/SinkTemperature.H b/CHT/SinkTemperature.H index 68493e54..ab15bce7 100644 --- a/CHT/SinkTemperature.H +++ b/CHT/SinkTemperature.H @@ -26,7 +26,7 @@ public: const std::string nameT); //- Write the sink temperature values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim); + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); //- Read the sink temperature values from the buffer void read(double* buffer, const unsigned int dim); diff --git a/CHT/Temperature.C b/CHT/Temperature.C index 3756471c..3459e840 100644 --- a/CHT/Temperature.C +++ b/CHT/Temperature.C @@ -15,10 +15,35 @@ preciceAdapter::CHT::Temperature::Temperature( dataType_ = scalar; } -void preciceAdapter::CHT::Temperature::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::CHT::Temperature::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (const auto& cell : T_->internalField()) + { + buffer[bufferIndex++] = cell; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(T_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy temperature into the buffer + buffer[bufferIndex++] = T_->internalField()[currentCell]; + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { @@ -54,12 +79,38 @@ void preciceAdapter::CHT::Temperature::write(double* buffer, bool meshConnectivi } } } + return bufferIndex; } void preciceAdapter::CHT::Temperature::read(double* buffer, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (auto& cell : T_->ref()) + { + cell = buffer[bufferIndex++]; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(T_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy temperature into the buffer + T_->ref()[currentCell] = buffer[bufferIndex++]; + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { @@ -84,11 +135,11 @@ bool preciceAdapter::CHT::Temperature::isLocationTypeSupported(const bool meshCo // always return true and offload the handling to the user. if (meshConnectivity) { - return true; + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::faceNodes); // we currently do not support meshConnectivity for volumeCenters } else { - return (this->locationType_ == LocationType::faceCenters); + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::volumeCenters); } } diff --git a/CHT/Temperature.H b/CHT/Temperature.H index d3e17d5b..a374d64d 100644 --- a/CHT/Temperature.H +++ b/CHT/Temperature.H @@ -4,6 +4,7 @@ #include "CouplingDataUser.H" #include "fvCFD.H" +#include "cellSet.H" namespace preciceAdapter { @@ -26,7 +27,7 @@ public: const std::string nameT); //- Write the temperature values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim); + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); //- Read the temperature values from the buffer void read(double* buffer, const unsigned int dim); diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..bd41fefb --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,37 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "Chourdakis" + given-names: "Gerasimos" + orcid: "https://orcid.org/0000-0002-3977-1385" +- family-names: "Schneider" + given-names: "David" + orcid: "https://orcid.org/0000-0002-3487-9688" +- family-names: "Uekermann" + given-names: "Benjamin" + orcid: "https://orcid.org/0000-0002-1314-9969" +title: "OpenFOAM-preCICE: Coupling OpenFOAM with External Solvers for Multi-Physics Simulations" +version: 1.1.0 +doi: 10.51560/ofj.v3.88 +date-released: 2022-02-08 +url: "https://journal.openfoam.com/index.php/ofj/article/view/88" +preferred-citation: + type: article + authors: + - family-names: "Chourdakis" + given-names: "Gerasimos" + orcid: "https://orcid.org/0000-0002-3977-1385" + - family-names: "Schneider" + given-names: "David" + orcid: "https://orcid.org/0000-0002-3487-9688" + - family-names: "Uekermann" + given-names: "Benjamin" + orcid: "https://orcid.org/0000-0002-1314-9969" + doi: "10.51560/ofj.v3.88" + journal: "OpenFOAM® Journal" + month: 2 + start: 1 # First page number + end: 25 # Last page number + title: "OpenFOAM-preCICE: Coupling OpenFOAM with External Solvers for Multi-Physics Simulations" + volume: 3 + year: 2023 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca2cd78a..b09fa65b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,10 @@ merge conflicts and we will merge these files at the time we release a new versi ## Code formatting -You can format all files with clang-format 11 by running `./tools/format-code.sh`. +We use [pre-commit](https://pre-commit.com/) to ensure consistent formatting. +Please install `pre-commit` and then install the hook in this repository with `pre-commit install`. +This ensures correct formatting for future commits. +Run `pre-commit run -va` to apply formatting retrospectively. ## Automatic checks @@ -24,3 +27,13 @@ There are also a few additional workflows that can be triggered manually: - `Check links`: checks the links in all markdown files to verify if they are still reachable. Members of the repository can trigger these workflows in the "Actions" tab. + +## System tests + +For non-trivial pull requests, we also need to execute [system regression tests](https://precice.org/dev-docs-system-tests.html), +to ensure that complete simulations still run and give the same results. +Because these take long, run on an external system, and consume significant resources, +we are only triggering these on demand. Add (or ask a maintainer to add) the +`trigger-system-tests` label to the pull request to trigger them. +The tests will only run once, so that further commits don't consume additional +resources: In case you want to re-trigger them, remove and add the label again. diff --git a/CouplingDataUser.C b/CouplingDataUser.C index 7e84250d..f90ef9a0 100644 --- a/CouplingDataUser.C +++ b/CouplingDataUser.C @@ -14,16 +14,14 @@ bool preciceAdapter::CouplingDataUser::hasVectorData() return dataType_ == vector; } -void preciceAdapter::CouplingDataUser::setDataID(int dataID) +void preciceAdapter::CouplingDataUser::setDataName(std::string dataName) { - dataID_ = dataID; - - return; + dataName_ = std::move(dataName); } -int preciceAdapter::CouplingDataUser::dataID() +const std::string& preciceAdapter::CouplingDataUser::dataName() { - return dataID_; + return dataName_; } void preciceAdapter::CouplingDataUser::setPatchIDs(std::vector patchIDs) @@ -31,6 +29,11 @@ void preciceAdapter::CouplingDataUser::setPatchIDs(std::vector patchIDs) patchIDs_ = patchIDs; } +void preciceAdapter::CouplingDataUser::setCellSetNames(std::vector cellSetNames) +{ + cellSetNames_ = cellSetNames; +} + void preciceAdapter::CouplingDataUser::setLocationsType(LocationType locationsType) { locationType_ = locationsType; @@ -45,6 +48,8 @@ void preciceAdapter::CouplingDataUser::checkDataLocation(const bool meshConnecti location = "faceCenters"; else if (locationType_ == LocationType::faceNodes) location = "faceNodes"; + else if (locationType_ == LocationType::volumeCenters) + location = "volumeCenters"; adapterInfo("\"locations = " + location + "\" is not supported for the data \"" + getDataName() + "\". Please select a different " diff --git a/CouplingDataUser.H b/CouplingDataUser.H index 3c994790..8faab32a 100644 --- a/CouplingDataUser.H +++ b/CouplingDataUser.H @@ -13,7 +13,8 @@ enum class LocationType { none, faceCenters, - faceNodes + faceNodes, + volumeCenters }; class CouplingDataUser @@ -32,8 +33,11 @@ protected: //- OpenFOAM patches that form the interface std::vector patchIDs_; - //- preCICE data ID - int dataID_; + //- Names of the OpenFOAM cell sets to be coupled (for volume coupling) + std::vector cellSetNames_; + + //- data name + std::string dataName_; //- location type of the interface LocationType locationType_ = LocationType::none; @@ -48,15 +52,18 @@ public: //- Returns true if the data are vector bool hasVectorData(); - //- Set the preCICE data ID - void setDataID(int dataID); + //- Set the data name + void setDataName(std::string dataName); - //- Get the preCICE data ID - int dataID(); + //- Get the data name + const std::string& dataName(); //- Set the patch IDs that form the interface void setPatchIDs(std::vector patchIDs); + //- Set the cellSetNames that form the overlapping cells of the interface + void setCellSetNames(std::vector cellSetNames); + //- Set the locations type of the interface void setLocationsType(LocationType locationsType); @@ -67,7 +74,8 @@ public: virtual void initialize(); //- Write the coupling data to the buffer - virtual void write(double* dataBuffer, bool meshConnectivity, const unsigned int dim) = 0; + // Returns the number of entries that were filles in the buffer (nComp * vertices) + virtual std::size_t write(double* dataBuffer, bool meshConnectivity, const unsigned int dim) = 0; //- Read the coupling data from the buffer virtual void read(double* dataBuffer, const unsigned int dim) = 0; diff --git a/FF/Alpha.C b/FF/Alpha.C new file mode 100644 index 00000000..f11d9c2e --- /dev/null +++ b/FF/Alpha.C @@ -0,0 +1,116 @@ +#include "Alpha.H" + +using namespace Foam; + +preciceAdapter::FF::Alpha::Alpha( + const Foam::fvMesh& mesh, + const std::string nameAlpha) +: Alpha_( + const_cast( + &mesh.lookupObject(nameAlpha))) +{ + dataType_ = scalar; +} + +std::size_t preciceAdapter::FF::Alpha::write(double* buffer, bool meshConnectivity, const unsigned int dim) +{ + int bufferIndex = 0; + + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (const auto& cell : Alpha_->internalField()) + { + buffer[bufferIndex++] = cell; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(Alpha_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy the alpha valus into the buffer + buffer[bufferIndex++] = Alpha_->internalField()[currentCell]; + } + } + } + } + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // For every cell of the patch + forAll(Alpha_->boundaryFieldRef()[patchID], i) + { + // Copy the Alpha into the buffer + buffer[bufferIndex++] = + Alpha_->boundaryFieldRef()[patchID][i]; + } + } + return bufferIndex; +} + +void preciceAdapter::FF::Alpha::read(double* buffer, const unsigned int dim) +{ + int bufferIndex = 0; + + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (auto& cell : Alpha_->ref()) + { + cell = buffer[bufferIndex++]; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(Alpha_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy the pressure into the buffer + Alpha_->ref()[currentCell] = buffer[bufferIndex++]; + } + } + } + } + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + // For every cell of the patch + forAll(Alpha_->boundaryFieldRef()[patchID], i) + { + Alpha_->boundaryFieldRef()[patchID][i] = buffer[bufferIndex++]; + } + } +} + +bool preciceAdapter::FF::Alpha::isLocationTypeSupported(const bool meshConnectivity) const +{ + if (meshConnectivity) + { + return (this->locationType_ == LocationType::faceCenters); + } + else + { + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::volumeCenters); + } +} + +std::string preciceAdapter::FF::Alpha::getDataName() const +{ + return "Alpha"; +} diff --git a/FF/Alpha.H b/FF/Alpha.H new file mode 100644 index 00000000..7e5feb99 --- /dev/null +++ b/FF/Alpha.H @@ -0,0 +1,43 @@ +#ifndef FF_ALPHA_H +#define FF_ALPHA_H + +#include "CouplingDataUser.H" + +#include "fvCFD.H" +#include "cellSet.H" + +namespace preciceAdapter +{ +namespace FF +{ + +//- Class that writes and reads Alpha +class Alpha : public CouplingDataUser +{ + +private: + //- Alpha field + Foam::volScalarField* Alpha_; + +public: + //- Constructor + Alpha( + const Foam::fvMesh& mesh, + const std::string nameAlpha); + + //- Write the Alpha values into the buffer + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); + + //- Read the Alpha values from the buffer + void read(double* buffer, const unsigned int dim); + + bool isLocationTypeSupported(const bool meshConnectivity) const override; + + //- Get the name of the current data field + std::string getDataName() const override; +}; + +} +} + +#endif diff --git a/FF/AlphaGradient.C b/FF/AlphaGradient.C new file mode 100644 index 00000000..00260801 --- /dev/null +++ b/FF/AlphaGradient.C @@ -0,0 +1,73 @@ +#include "AlphaGradient.H" +#include "mixedFvPatchFields.H" + +using namespace Foam; + +preciceAdapter::FF::AlphaGradient::AlphaGradient( + const Foam::fvMesh& mesh, + const std::string nameAlpha) +: Alpha_( + const_cast( + &mesh.lookupObject(nameAlpha))) +{ + dataType_ = scalar; +} + +std::size_t preciceAdapter::FF::AlphaGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // Get the Alpha gradient boundary patch + const scalarField gradientPatch((Alpha_->boundaryFieldRef()[patchID]) + .snGrad()); + + // For every cell of the patch + forAll(gradientPatch, i) + { + // Copy the Alpha gradient into the buffer + buffer[bufferIndex++] = + -gradientPatch[i]; + } + } + return bufferIndex; +} + +void preciceAdapter::FF::AlphaGradient::read(double* buffer, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // Get the Alpha gradient boundary patch + scalarField& gradientPatch = + refCast( + Alpha_->boundaryFieldRef()[patchID]) + .gradient(); + + // For every cell of the patch + forAll(gradientPatch, i) + { + // Set the Alpha gradient as the buffer value + gradientPatch[i] = + buffer[bufferIndex++]; + } + } +} + +bool preciceAdapter::FF::AlphaGradient::isLocationTypeSupported(const bool meshConnectivity) const +{ + return (this->locationType_ == LocationType::faceCenters); +} + +std::string preciceAdapter::FF::AlphaGradient::getDataName() const +{ + return "AlphaGradient"; +} diff --git a/FF/AlphaGradient.H b/FF/AlphaGradient.H new file mode 100644 index 00000000..b538f009 --- /dev/null +++ b/FF/AlphaGradient.H @@ -0,0 +1,42 @@ +#ifndef FF_ALPHA_GRADIENT_H +#define FF_ALPHA_GRADIENT_H + +#include "CouplingDataUser.H" + +#include "fvCFD.H" + +namespace preciceAdapter +{ +namespace FF +{ + +//- Class that writes and reads Alpha gradient +class AlphaGradient : public CouplingDataUser +{ + +private: + //- Alpha field + Foam::volScalarField* Alpha_; + +public: + //- Constructor + AlphaGradient( + const Foam::fvMesh& mesh, + const std::string nameAlpha); + + //- Write the Alpha gradient values into the buffer + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); + + //- Read the Alpha gradient values from the buffer + void read(double* buffer, const unsigned int dim); + + bool isLocationTypeSupported(const bool meshConnectivity) const override; + + //- Get the name of the current data field + std::string getDataName() const override; +}; + +} +} + +#endif diff --git a/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.C b/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.C new file mode 100644 index 00000000..320a6ca2 --- /dev/null +++ b/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.C @@ -0,0 +1,181 @@ +#include "coupledPressureFvPatchField.H" +#include "addToRunTimeSelectionTable.H" +#include "surfaceFields.H" + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::coupledPressureFvPatchField::coupledPressureFvPatchField( + const fvPatch& p, + const DimensionedField& iF) +: fixedFluxExtrapolatedPressureFvPatchScalarField(p, iF), + refValue_(p.size(), Zero), + refGrad_(p.size(), Zero), + valueFraction_(p.size(), Zero) +{ +} + + +Foam::coupledPressureFvPatchField::coupledPressureFvPatchField( + const fvPatch& p, + const DimensionedField& iF, + const dictionary& dict, + const bool valueRequired) +: fixedFluxExtrapolatedPressureFvPatchScalarField(p, iF, dict), + refValue_("refValue", dict, p.size()), + valueFraction_(p.size(), Zero), + phiName_(dict.getOrDefault("phi", "phi")), + uName_(dict.getOrDefault("U", "U")) +{ + if (dict.found("refGradient")) + { + this->refGrad() = scalarField("refGradient", dict, p.size()); + } + else + { + this->refGrad() = scalarField(p.size(), Zero); + } +} + + +Foam::coupledPressureFvPatchField::coupledPressureFvPatchField( + const coupledPressureFvPatchField& ptf, + const fvPatch& p, + const DimensionedField& iF, + const fvPatchFieldMapper& mapper) +: fixedFluxExtrapolatedPressureFvPatchScalarField(ptf, p, iF, mapper), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ + if (notNull(iF) && mapper.hasUnmapped()) + { + WarningInFunction + << "On field " << iF.name() << " patch " << p.name() + << " patchField " << this->type() + << " : mapper does not map all values." << nl + << " To avoid this warning fully specify the mapping in derived" + << " patch fields." << endl; + } +} + + +Foam::coupledPressureFvPatchField::coupledPressureFvPatchField( + const coupledPressureFvPatchField& ptf) +: fixedFluxExtrapolatedPressureFvPatchScalarField(ptf), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ +} + + +Foam::coupledPressureFvPatchField::coupledPressureFvPatchField( + const coupledPressureFvPatchField& ptf, + const DimensionedField& iF) +: fixedFluxExtrapolatedPressureFvPatchScalarField(ptf, iF), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +Foam::tmp +Foam::coupledPressureFvPatchField::snGrad() const +{ + return valueFraction_ + * (refValue_ - this->patchInternalField()) + * this->patch().deltaCoeffs() + + (1.0 - valueFraction_) * refGrad_; +} + +void Foam::coupledPressureFvPatchField::updateCoeffs() +{ + const Foam::surfaceScalarField* phi = &db().lookupObject(phiName_); + const scalarField& phip = phi->boundaryField()[this->patch().index()]; + const Foam::volVectorField* U = &db().lookupObject(uName_); + const vectorField& Up = U->boundaryField()[this->patch().index()]; + const vectorField n = this->patch().nf(); + + int t0 = this->patch().boundaryMesh().mesh().time().startTimeIndex(); + int t = this->patch().boundaryMesh().mesh().time().timeIndex(); + if (t - t0 == 1) + { + this->valueFraction() = pos0(Up & n); + } + else + { + this->valueFraction() = pos0(phip); + } + fixedFluxExtrapolatedPressureFvPatchScalarField::updateCoeffs(); +} + +void Foam::coupledPressureFvPatchField::evaluate(const Pstream::commsTypes) +{ + if (!this->updated()) + { + this->updateCoeffs(); + } + + scalarField::operator=( + valueFraction_* refValue_ + + (1.0 - valueFraction_) + * (this->patchInternalField() + + refGrad_ / this->patch().deltaCoeffs())); + + fvPatchScalarField::evaluate(); +} + +Foam::tmp +Foam::coupledPressureFvPatchField::valueInternalCoeffs( + const tmp&) const +{ + return (pTraits::one) * (1.0 - valueFraction_); +} + + +Foam::tmp +Foam::coupledPressureFvPatchField::valueBoundaryCoeffs( + const tmp&) const +{ + return valueFraction_ * refValue_ + + (1.0 - valueFraction_) * refGrad_ / this->patch().deltaCoeffs(); +} + + +Foam::tmp +Foam::coupledPressureFvPatchField::gradientInternalCoeffs() const +{ + return -(pTraits::one) * valueFraction_ * this->patch().deltaCoeffs(); +} + + +Foam::tmp +Foam::coupledPressureFvPatchField::gradientBoundaryCoeffs() const +{ + return valueFraction_ * this->patch().deltaCoeffs() * refValue_ + + (1.0 - valueFraction_) * refGrad_; +} + + +void Foam::coupledPressureFvPatchField::write(Ostream& os) const +{ + fvPatchScalarField::write(os); + this->writeEntry("value", os); + this->valueFraction().writeEntry("valueFraction", os); + this->refValue().writeEntry("refValue", os); +} + + +// ************************************************************************* // + +namespace Foam +{ +makePatchTypeField( + fixedFluxExtrapolatedPressureFvPatchScalarField, + coupledPressureFvPatchField); +} diff --git a/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.H b/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.H new file mode 100644 index 00000000..da9f875a --- /dev/null +++ b/FF/BoundaryConditions/coupledPressure/coupledPressureFvPatchField.H @@ -0,0 +1,249 @@ +/*---------------------------------------------------------------------------*\ +Class + Foam::coupledPressureFvPatchField + +Description + This boundary condition is a pressure inlet-outlet condition. + It acts as a fixedFluxExtrapolated pressure boundary patch for inflow faces and as a fixedValue at outflow faces. + +Usage + \table + Property | Description | Required | Default value + refValue | reference Pressure values | yes | + refGradient | reference Pressure gradient values | no | uniform 0 + phi | name of flux field | no | "phi" + U | name of velocity field | no | "U" + \endtable + + Example of the boundary condition specification: + \verbatim + + { + type coupledPressure; + refValue uniform 0; // Example for Foam::scalar field usage + } + \endverbatim + +SourceFiles + coupledPressureFvPatchField.C + +\*---------------------------------------------------------------------------*/ + +#ifndef coupledPressureFvPatchField_H +#define coupledPressureFvPatchField_H + +#include "fvPatchField.H" +#include "fixedFluxExtrapolatedPressureFvPatchScalarField.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class coupledPressureFvPatchField Declaration +\*---------------------------------------------------------------------------*/ + +class coupledPressureFvPatchField +: public fixedFluxExtrapolatedPressureFvPatchScalarField +{ + +private: + //- Value field + scalarField refValue_; + + //- Normal gradient field + scalarField refGrad_; + + //- Fraction (0-1) of value used for boundary condition + scalarField valueFraction_; + + //- Name of flux field + word phiName_; + + //- Name of velocity field + word uName_; + +public: + //- Runtime type information + TypeName("coupledPressure"); + + + // Constructors + + //- Construct from patch and internal field + coupledPressureFvPatchField( + const fvPatch&, + const DimensionedField&); + + //- Construct from patch, internal field and dictionary + coupledPressureFvPatchField( + const fvPatch&, + const DimensionedField&, + const dictionary&, + const bool valueRequired = true); + + //- Construct by mapping the given coupledPressureFvPatchField + // onto a new patch + coupledPressureFvPatchField( + const coupledPressureFvPatchField&, + const fvPatch&, + const DimensionedField&, + const fvPatchFieldMapper&); + + //- Construct as copy + coupledPressureFvPatchField( + const coupledPressureFvPatchField&); + + //- Construct and return a clone + virtual tmp clone() const + { + return tmp( + new coupledPressureFvPatchField(*this)); + } + + //- Construct as copy setting internal field reference + coupledPressureFvPatchField( + const coupledPressureFvPatchField&, + const DimensionedField&); + + //- Construct and return a clone setting internal field reference + virtual tmp clone( + const DimensionedField& iF) const + { + return tmp( + new coupledPressureFvPatchField(*this, iF)); + } + + + // Member functions + + + // Attributes + + //- Return true if this patch field fixes a value. + // Needed to check if a level has to be specified while solving + // Poissons equations. + virtual bool fixesValue() const + { + return true; + } + + //- Return false: this patch field is not altered by assignment + virtual bool assignable() const + { + return false; + } + + // Evaluation functions + void evaluate(const Pstream::commsTypes commsType = + Pstream::commsTypes::blocking); + //- Return the matrix diagonal coefficients corresponding to the + // evaluation of the value of this patchField with given weights + virtual tmp valueInternalCoeffs( + const tmp&) const; + + //- Return the matrix source coefficients corresponding to the + // evaluation of the value of this patchField with given weights + virtual tmp valueBoundaryCoeffs( + const tmp&) const; + + //- Return the matrix diagonal coefficients corresponding to the + // evaluation of the gradient of this patchField + virtual tmp gradientInternalCoeffs() const; + + //- Return the matrix source coefficients corresponding to the + // evaluation of the gradient of this patchField + virtual tmp gradientBoundaryCoeffs() const; + + // Return defining fields + + virtual Foam::scalarField& refValue() + { + return refValue_; + } + + virtual const Foam::scalarField& refValue() const + { + return refValue_; + } + + virtual Foam::scalarField& refGrad() + { + return refGrad_; + } + + virtual const Foam::scalarField& refGrad() const + { + return refGrad_; + } + + virtual Foam::scalarField& gradient() + { + return refGrad_; + } + + virtual const Foam::scalarField& gradient() const + { + return refGrad_; + } + + virtual scalarField& valueFraction() + { + return valueFraction_; + } + + virtual const scalarField& valueFraction() const + { + return valueFraction_; + } + + //- Return gradient at boundary + virtual tmp snGrad() const; + + + void updateCoeffs(); + + //- Write + virtual void write(Ostream&) const; + + + // Member operators + + virtual void operator=(const UList&) {} + + virtual void operator=(const fvPatchScalarField&) {} + virtual void operator+=(const fvPatchScalarField&) {} + virtual void operator-=(const fvPatchScalarField&) {} + virtual void operator*=(const fvPatchScalarField&) {} + virtual void operator/=(const fvPatchScalarField&) {} + + virtual void operator+=(const scalarField&) {} + virtual void operator-=(const scalarField&) {} + + virtual void operator*=(const scalarField&) {} + virtual void operator/=(const scalarField&) {} + + virtual void operator=(const Foam::scalar&) {} + virtual void operator+=(const Foam::scalar&) {} + virtual void operator-=(const Foam::scalar&) {} + virtual void operator*=(const Foam::scalar) {} + virtual void operator/=(const Foam::scalar) {} +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// #ifdef NoRepository +// #include "coupledPressureFvPatchField.C" +// #endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.C b/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.C new file mode 100644 index 00000000..1546477c --- /dev/null +++ b/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.C @@ -0,0 +1,178 @@ +#include "coupledVelocityFvPatchField.H" +#include "dictionary.H" +#include "addToRunTimeSelectionTable.H" + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + + +Foam::coupledVelocityFvPatchField::coupledVelocityFvPatchField( + const fvPatch& p, + const DimensionedField& iF) +: fvPatchField(p, iF), + refValue_(p.size(), Zero), + refGrad_(p.size(), Zero), + valueFraction_(p.size(), Zero) +{ +} + + +Foam::coupledVelocityFvPatchField::coupledVelocityFvPatchField( + const fvPatch& p, + const DimensionedField& iF, + const dictionary& dict) +: fvPatchField(p, iF), + refValue_("refValue", dict, p.size()), + valueFraction_(p.size(), Zero), + phiName_(dict.getOrDefault("phi", "phi")) +{ + if (dict.found("refGradient")) + { + this->refGrad() = vectorField("refGradient", dict, p.size()); + } + else + { + this->refGrad() = vectorField(p.size(), Zero); + } + + vectorField::operator=( + valueFraction_* refValue_ + + (1.0 - valueFraction_) + * (this->patchInternalField() + + refGrad_ / this->patch().deltaCoeffs())); +} + + +Foam::coupledVelocityFvPatchField::coupledVelocityFvPatchField( + const coupledVelocityFvPatchField& ptf, + const fvPatch& p, + const DimensionedField& iF, + const fvPatchFieldMapper& mapper) +: fvPatchField(ptf, p, iF, mapper), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ +} + + +Foam::coupledVelocityFvPatchField::coupledVelocityFvPatchField( + const coupledVelocityFvPatchField& ptf) +: fvPatchField(ptf), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ +} + + +Foam::coupledVelocityFvPatchField::coupledVelocityFvPatchField( + const coupledVelocityFvPatchField& ptf, + const DimensionedField& iF) +: fvPatchField(ptf, iF), + refValue_(ptf.refValue_), + refGrad_(ptf.refGrad_), + valueFraction_(ptf.valueFraction_) +{ +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::tmp Foam::coupledVelocityFvPatchField::snGrad() const +{ + return valueFraction_ + * (refValue_ - this->patchInternalField()) + * this->patch().deltaCoeffs() + + (1.0 - valueFraction_) * refGrad_; +} + +void Foam::coupledVelocityFvPatchField::updateCoeffs() +{ + if (this->updated()) + { + return; + } + const Foam::surfaceScalarField* phi = &db().lookupObject(phiName_); + const scalarField& phip = phi->boundaryField()[this->patch().index()]; + const vectorField n = this->patch().nf(); + + int t0 = this->patch().boundaryMesh().mesh().time().startTimeIndex(); + int t = this->patch().boundaryMesh().mesh().time().timeIndex(); + if (t - t0 == 1) + { + this->valueFraction() = 1 - pos0(refValue_ & n); + } + else + { + this->valueFraction() = 1 - pos0(phip); + } + fvPatchVectorField::updateCoeffs(); +} + +void Foam::coupledVelocityFvPatchField::evaluate(const Pstream::commsTypes p) +{ + if (!this->updated()) + { + this->updateCoeffs(); + } + + vectorField::operator=( + valueFraction_* refValue_ + + (1.0 - valueFraction_) + * (this->patchInternalField() + + refGrad_ / this->patch().deltaCoeffs())); + + fvPatchVectorField::evaluate(); +} + + +Foam::tmp> +Foam::coupledVelocityFvPatchField::valueInternalCoeffs( + const tmp&) const +{ + return (pTraits::one) * (1.0 - valueFraction_); +} + + +Foam::tmp> +Foam::coupledVelocityFvPatchField::valueBoundaryCoeffs( + const tmp&) const +{ + return valueFraction_ * refValue_ + + (1.0 - valueFraction_) * refGrad_ / this->patch().deltaCoeffs(); +} + + +Foam::tmp> +Foam::coupledVelocityFvPatchField::gradientInternalCoeffs() const +{ + return -(pTraits::one) * valueFraction_ * this->patch().deltaCoeffs(); +} + + +Foam::tmp> +Foam::coupledVelocityFvPatchField::gradientBoundaryCoeffs() const +{ + return valueFraction_ * this->patch().deltaCoeffs() * refValue_ + + (1.0 - valueFraction_) * refGrad_; +} + + +void Foam::coupledVelocityFvPatchField::write(Ostream& os) const +{ + fvPatchField::write(os); + this->writeEntry("value", os); + this->valueFraction().writeEntry("valueFraction", os); + this->refValue().writeEntry("refValue", os); +} + + +// ************************************************************************* // + +namespace Foam +{ +makePatchTypeField( + fvPatchVectorField, + coupledVelocityFvPatchField); +} diff --git a/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.H b/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.H new file mode 100644 index 00000000..dadc1f2f --- /dev/null +++ b/FF/BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.H @@ -0,0 +1,218 @@ +/*---------------------------------------------------------------------------*\ +Class + Foam::coupledVelocityFvPatchField + +Description + This boundary condition is a velocity inlet-outlet. + It acts as a fixedValue boundary patch for inflow faces and as a fixedGradient at outflow faces. + It is essentially a type-specific version of the inletOutlet condition of OpenFOAM. + +Usage + \table + Property | Description | Required | Default value + refValue | reference Velocity values | yes | + refGradient | reference Velocity gradient values | no | uniform (0 0 0) + phi | name of flux field | no | "phi" + \endtable + + Example of the boundary condition specification: + \verbatim + + { + type coupledVelocity; + refValue uniform (0 0 0); + } + \endverbatim + +SourceFiles + coupledVelocityFvPatchField.C + +\*---------------------------------------------------------------------------*/ + +#ifndef coupledVelocityFvPatchField_H +#define coupledVelocityFvPatchField_H + +#include "fvPatchFields.H" +#include "fvCFD.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class coupledVelocityFvPatchField Declaration +\*---------------------------------------------------------------------------*/ + +class coupledVelocityFvPatchField +: public fvPatchVectorField +{ +private: + // Private data + + //- Value field + vectorField refValue_; + + //- Normal gradient field + vectorField refGrad_; + + //- Fraction (0-1) of value used for boundary condition + scalarField valueFraction_; + + //- Name of flux field + word phiName_; + +public: + //- Runtime type information + TypeName("coupledVelocity"); + + + // Constructors + + //- Construct from patch and internal field + coupledVelocityFvPatchField( + const fvPatch&, + const DimensionedField&); + + //- Construct from patch, internal field and dictionary + coupledVelocityFvPatchField( + const fvPatch&, + const DimensionedField&, + const dictionary&); + + //- Construct by mapping the given coupledVelocityFvPatchField + // onto a new patch + coupledVelocityFvPatchField( + const coupledVelocityFvPatchField&, + const fvPatch&, + const DimensionedField&, + const fvPatchFieldMapper&); + + //- Construct as copy + coupledVelocityFvPatchField( + const coupledVelocityFvPatchField&); + + //- Construct and return a clone + virtual tmp clone() const + { + return tmp( + new coupledVelocityFvPatchField(*this)); + } + + //- Construct as copy setting internal field reference + coupledVelocityFvPatchField( + const coupledVelocityFvPatchField&, + const DimensionedField&); + + //- Construct and return a clone setting internal field reference + virtual tmp> clone( + const DimensionedField& iF) const + { + return tmp>( + new coupledVelocityFvPatchField(*this, iF)); + } + + + // Member functions + //- Return true if this patch field fixes a value. + // Needed to check if a level has to be specified while solving + // Poissons equations. + virtual bool fixesValue() const + { + return true; + } + + //- Return false: this patch field is not altered by assignment + virtual bool assignable() const + { + return true; + } + + // Evaluation functions + + //- Return neighbour coupled internal cell data + virtual vectorField& refValue() + { + return refValue_; + } + + virtual const vectorField& refValue() const + { + return refValue_; + } + + virtual vectorField& refGrad() + { + return refGrad_; + } + + virtual const vectorField& refGrad() const + { + return refGrad_; + } + + virtual vectorField& gradient() + { + return refGrad_; + } + + virtual const vectorField& gradient() const + { + return refGrad_; + } + + virtual scalarField& valueFraction() + { + return valueFraction_; + } + + virtual const scalarField& valueFraction() const + { + return valueFraction_; + } + + //- Return gradient at boundary + virtual tmp snGrad() const; + + void updateCoeffs(); + + //- Evaluate the patch field + virtual void evaluate( + const Pstream::commsTypes commsType = + Pstream::commsTypes::blocking); + + //- Return the matrix diagonal coefficients corresponding to the + // evaluation of the value of this patchField with given weights + virtual tmp> valueInternalCoeffs( + const tmp&) const; + + //- Return the matrix source coefficients corresponding to the + // evaluation of the value of this patchField with given weights + virtual tmp> valueBoundaryCoeffs( + const tmp&) const; + + //- Return the matrix diagonal coefficients corresponding to the + // evaluation of the gradient of this patchField + virtual tmp> gradientInternalCoeffs() const; + + //- Return the matrix source coefficients corresponding to the + // evaluation of the gradient of this patchField + virtual tmp> gradientBoundaryCoeffs() const; + + //- Write + virtual void write(Ostream&) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/FF/FF.C b/FF/FF.C index 6bf0476b..2c2144ee 100644 --- a/FF/FF.C +++ b/FF/FF.C @@ -59,6 +59,22 @@ bool preciceAdapter::FF::FluidFluid::readConfig(const IOdictionary& adapterConfi nameP_ = FFdict.lookupOrDefault("nameP", "p"); DEBUG(adapterInfo(" pressure field name : " + nameP_)); + // Read the name of the temperature field (if different) + nameT_ = FFdict.lookupOrDefault("nameT", "T"); + DEBUG(adapterInfo(" temperature field name : " + nameT_)); + + // Read the name of the phase variable field (if different) + nameAlpha_ = FFdict.lookupOrDefault("nameAlpha", "alpha"); + DEBUG(adapterInfo(" phase variable (alpha) field name : " + nameAlpha_)); + + // Read the name of the face flux field (if different) + namePhi_ = FFdict.lookupOrDefault("namePhi", "phi"); + DEBUG(adapterInfo(" face flux field name : " + namePhi_)); + + // Check whether to enable flux correction for velocity + fluxCorrection_ = FFdict.lookupOrDefault("fluxCorrection", false); + DEBUG(adapterInfo(" flux correction of velocity is set to : " + std::to_string(fluxCorrection_))); + return true; } @@ -112,7 +128,7 @@ bool preciceAdapter::FF::FluidFluid::addWriters(std::string dataName, Interface* { interface->addCouplingDataWriter( dataName, - new Velocity(mesh_, nameU_)); + new Velocity(mesh_, nameU_, namePhi_, fluxCorrection_)); DEBUG(adapterInfo("Added writer: Velocity.")); } else if (dataName.find("PressureGradient") == 0) @@ -129,6 +145,41 @@ bool preciceAdapter::FF::FluidFluid::addWriters(std::string dataName, Interface* new Pressure(mesh_, nameP_)); DEBUG(adapterInfo("Added writer: Pressure.")); } + else if (dataName.find("FlowTemperatureGradient") == 0) + { + interface->addCouplingDataWriter( + dataName, + new TemperatureGradient(mesh_, nameT_)); + DEBUG(adapterInfo("Added writer: Flow Temperature Gradient.")); + } + else if (dataName.find("FlowTemperature") == 0) + { + interface->addCouplingDataWriter( + dataName, + new Temperature(mesh_, nameT_)); + DEBUG(adapterInfo("Added writer: Flow Temperature.")); + } + else if (dataName.find("AlphaGradient") == 0) + { + interface->addCouplingDataWriter( + dataName, + new AlphaGradient(mesh_, nameAlpha_)); + DEBUG(adapterInfo("Added writer: Alpha Gradient.")); + } + else if (dataName.find("Alpha") == 0) + { + interface->addCouplingDataWriter( + dataName, + new Alpha(mesh_, nameAlpha_)); + DEBUG(adapterInfo("Added writer: Alpha.")); + } + else if (dataName.find("Phi") == 0) + { + interface->addCouplingDataWriter( + dataName, + new Phi(mesh_, namePhi_)); + DEBUG(adapterInfo("Added writer: Phi.")); + } else { found = false; @@ -158,7 +209,7 @@ bool preciceAdapter::FF::FluidFluid::addReaders(std::string dataName, Interface* { interface->addCouplingDataReader( dataName, - new Velocity(mesh_, nameU_)); + new Velocity(mesh_, nameU_, namePhi_)); DEBUG(adapterInfo("Added reader: Velocity.")); } else if (dataName.find("PressureGradient") == 0) @@ -175,6 +226,41 @@ bool preciceAdapter::FF::FluidFluid::addReaders(std::string dataName, Interface* new Pressure(mesh_, nameP_)); DEBUG(adapterInfo("Added reader: Pressure.")); } + else if (dataName.find("FlowTemperatureGradient") == 0) + { + interface->addCouplingDataReader( + dataName, + new TemperatureGradient(mesh_, nameT_)); + DEBUG(adapterInfo("Added reader: Flow Temperature Gradient.")); + } + else if (dataName.find("FlowTemperature") == 0) + { + interface->addCouplingDataReader( + dataName, + new Temperature(mesh_, nameT_)); + DEBUG(adapterInfo("Added reader: Flow Temperature.")); + } + else if (dataName.find("AlphaGradient") == 0) + { + interface->addCouplingDataReader( + dataName, + new AlphaGradient(mesh_, nameAlpha_)); + DEBUG(adapterInfo("Added reader: Alpha Gradient.")); + } + else if (dataName.find("Alpha") == 0) + { + interface->addCouplingDataReader( + dataName, + new Alpha(mesh_, nameAlpha_)); + DEBUG(adapterInfo("Added reader: Alpha.")); + } + else if (dataName.find("Phi") == 0) + { + interface->addCouplingDataReader( + dataName, + new Phi(mesh_, namePhi_)); + DEBUG(adapterInfo("Added reader: Phi.")); + } else { found = false; diff --git a/FF/FF.H b/FF/FF.H index ded126e0..77629442 100644 --- a/FF/FF.H +++ b/FF/FF.H @@ -5,8 +5,13 @@ #include "FF/Velocity.H" #include "FF/Pressure.H" +#include "FF/Temperature.H" +#include "FF/Alpha.H" #include "FF/PressureGradient.H" #include "FF/VelocityGradient.H" +#include "FF/TemperatureGradient.H" +#include "FF/AlphaGradient.H" +#include "FF/Phi.H" #include "fvCFD.H" @@ -33,6 +38,18 @@ protected: //- Name of the pressure field std::string nameP_ = "p"; + //- Name of the temperature field + std::string nameT_ = "T"; + + //- Name of the phase variable (alpha) field + std::string nameAlpha_ = "alpha"; + + //- Name of the face flux field + std::string namePhi_ = "phi"; + + //- Flux correction of velocity + bool fluxCorrection_ = false; + //- Determine the solver type std::string determineSolverType(); diff --git a/FF/ModuleFF.C b/FF/ModuleFF.C new file mode 100644 index 00000000..21d191ea --- /dev/null +++ b/FF/ModuleFF.C @@ -0,0 +1,13 @@ +// Central inlude file to reduce the number of build targets and build time +#include "FF.C" +#include "Velocity.C" +#include "VelocityGradient.C" +#include "Pressure.C" +#include "PressureGradient.C" +#include "Temperature.C" +#include "TemperatureGradient.C" +#include "Alpha.C" +#include "AlphaGradient.C" +#include "Phi.C" +#include "BoundaryConditions/coupledPressure/coupledPressureFvPatchField.C" +#include "BoundaryConditions/coupledVelocity/coupledVelocityFvPatchField.C" diff --git a/FF/Phi.C b/FF/Phi.C new file mode 100644 index 00000000..d2001395 --- /dev/null +++ b/FF/Phi.C @@ -0,0 +1,59 @@ +#include "Phi.H" + +using namespace Foam; + +preciceAdapter::FF::Phi::Phi( + const Foam::fvMesh& mesh, + const std::string namePhi) +: phi_( + const_cast( + &mesh.lookupObject(namePhi))) +{ + dataType_ = scalar; +} + +std::size_t preciceAdapter::FF::Phi::write(double* buffer, bool meshConnectivity, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // For every cell of the patch + forAll(phi_->boundaryFieldRef()[patchID], i) + { + // Copy the Phi into the buffer + buffer[bufferIndex++] = + phi_->boundaryFieldRef()[patchID][i]; + } + } + return bufferIndex; +} + +void preciceAdapter::FF::Phi::read(double* buffer, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + forAll(phi_->boundaryFieldRef()[patchID], i) + { + phi_->boundaryFieldRef()[patchID][i] = -buffer[bufferIndex++]; + } + } +} + +bool preciceAdapter::FF::Phi::isLocationTypeSupported(const bool meshConnectivity) const +{ + return (this->locationType_ == LocationType::faceCenters); +} + +std::string preciceAdapter::FF::Phi::getDataName() const +{ + return "Phi"; +} diff --git a/FF/Phi.H b/FF/Phi.H new file mode 100644 index 00000000..0b42c6ad --- /dev/null +++ b/FF/Phi.H @@ -0,0 +1,42 @@ +#ifndef FF_PHI_H +#define FF_PHI_H + +#include "CouplingDataUser.H" + +#include "fvCFD.H" + +namespace preciceAdapter +{ +namespace FF +{ + +//- Class that writes and reads the flux phi +class Phi : public CouplingDataUser +{ + +private: + //- Phi field + Foam::surfaceScalarField* phi_; + +public: + //- Constructor + Phi( + const Foam::fvMesh& mesh, + const std::string namePhi); + + //- Write the Phi values into the buffer + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); + + //- Read the Phi values from the buffer + void read(double* buffer, const unsigned int dim); + + bool isLocationTypeSupported(const bool meshConnectivity) const override; + + //- Get the name of the current data field + std::string getDataName() const override; +}; + +} +} + +#endif diff --git a/FF/Pressure.C b/FF/Pressure.C index 2d8566e5..5e8b94db 100644 --- a/FF/Pressure.C +++ b/FF/Pressure.C @@ -1,4 +1,5 @@ #include "Pressure.H" +#include "coupledPressureFvPatchField.H" using namespace Foam; @@ -12,10 +13,35 @@ preciceAdapter::FF::Pressure::Pressure( dataType_ = scalar; } -void preciceAdapter::FF::Pressure::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FF::Pressure::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (const auto& cell : p_->internalField()) + { + buffer[bufferIndex++] = cell; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(p_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy the pressure into the buffer + buffer[bufferIndex++] = p_->internalField()[currentCell]; + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { @@ -29,22 +55,58 @@ void preciceAdapter::FF::Pressure::write(double* buffer, bool meshConnectivity, p_->boundaryFieldRef()[patchID][i]; } } + return bufferIndex; } void preciceAdapter::FF::Pressure::read(double* buffer, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (auto& cell : p_->ref()) + { + cell = buffer[bufferIndex++]; + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(p_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // Copy the pressure into the buffer + p_->ref()[currentCell] = buffer[bufferIndex++]; + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { int patchID = patchIDs_.at(j); + // Get the pressure value boundary patch + scalarField* valuePatchPtr = &p_->boundaryFieldRef()[patchID]; + if (isA(p_->boundaryFieldRef()[patchID])) + { + valuePatchPtr = &refCast( + p_->boundaryFieldRef()[patchID]) + .refValue(); + } + scalarField& valuePatch = *valuePatchPtr; + // For every cell of the patch forAll(p_->boundaryFieldRef()[patchID], i) { // Set the pressure as the buffer value - p_->boundaryFieldRef()[patchID][i] = + valuePatch[i] = buffer[bufferIndex++]; } } @@ -52,7 +114,14 @@ void preciceAdapter::FF::Pressure::read(double* buffer, const unsigned int dim) bool preciceAdapter::FF::Pressure::isLocationTypeSupported(const bool meshConnectivity) const { - return (this->locationType_ == LocationType::faceCenters); + if (meshConnectivity) + { + return (this->locationType_ == LocationType::faceCenters); + } + else + { + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::volumeCenters); + } } std::string preciceAdapter::FF::Pressure::getDataName() const diff --git a/FF/Pressure.H b/FF/Pressure.H index 32993489..ecd06a02 100644 --- a/FF/Pressure.H +++ b/FF/Pressure.H @@ -4,6 +4,7 @@ #include "CouplingDataUser.H" #include "fvCFD.H" +#include "cellSet.H" namespace preciceAdapter { @@ -25,7 +26,7 @@ public: const std::string nameP); //- Write the pressure values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim); + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); //- Read the pressure values from the buffer void read(double* buffer, const unsigned int dim); diff --git a/FF/PressureGradient.C b/FF/PressureGradient.C index ef8dd9ff..ca125179 100644 --- a/FF/PressureGradient.C +++ b/FF/PressureGradient.C @@ -12,7 +12,7 @@ preciceAdapter::FF::PressureGradient::PressureGradient( dataType_ = scalar; } -void preciceAdapter::FF::PressureGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FF::PressureGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; @@ -33,6 +33,7 @@ void preciceAdapter::FF::PressureGradient::write(double* buffer, bool meshConnec -gradientPatch[i]; } } + return bufferIndex; } void preciceAdapter::FF::PressureGradient::read(double* buffer, const unsigned int dim) diff --git a/FF/PressureGradient.H b/FF/PressureGradient.H index 95094f3c..47db220e 100644 --- a/FF/PressureGradient.H +++ b/FF/PressureGradient.H @@ -25,7 +25,7 @@ public: const std::string nameP); //- Write the pressure gradient values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim); + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); //- Read the pressure gradient values from the buffer void read(double* buffer, const unsigned int dim); diff --git a/FF/Temperature.C b/FF/Temperature.C new file mode 100644 index 00000000..4aff8611 --- /dev/null +++ b/FF/Temperature.C @@ -0,0 +1,61 @@ +#include "Temperature.H" + +using namespace Foam; + +preciceAdapter::FF::Temperature::Temperature( + const Foam::fvMesh& mesh, + const std::string nameT) +: T_( + const_cast( + &mesh.lookupObject(nameT))) +{ + dataType_ = scalar; +} + +std::size_t preciceAdapter::FF::Temperature::write(double* buffer, bool meshConnectivity, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + scalarField gradientPatch((T_->boundaryFieldRef()[patchID]) + .snGrad()); + + // For every cell of the patch + forAll(T_->boundaryFieldRef()[patchID], i) + { + // Copy the pressure into the buffer + buffer[bufferIndex++] = + T_->boundaryFieldRef()[patchID][i]; + } + } + return bufferIndex; +} + +void preciceAdapter::FF::Temperature::read(double* buffer, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + // For every cell of the patch + forAll(T_->boundaryFieldRef()[patchID], i) + { + T_->boundaryFieldRef()[patchID][i] = buffer[bufferIndex++]; + } + } +} + +bool preciceAdapter::FF::Temperature::isLocationTypeSupported(const bool meshConnectivity) const +{ + return (this->locationType_ == LocationType::faceCenters); +} + +std::string preciceAdapter::FF::Temperature::getDataName() const +{ + return "Temperature"; +} diff --git a/FF/Temperature.H b/FF/Temperature.H new file mode 100644 index 00000000..da6daad9 --- /dev/null +++ b/FF/Temperature.H @@ -0,0 +1,42 @@ +#ifndef FF_TEMPERATURE_H +#define FF_TEMPERATURE_H + +#include "CouplingDataUser.H" + +#include "fvCFD.H" + +namespace preciceAdapter +{ +namespace FF +{ + +//- Class that writes and reads temperature +class Temperature : public CouplingDataUser +{ + +private: + //- Temperature field + Foam::volScalarField* T_; + +public: + //- Constructor + Temperature( + const Foam::fvMesh& mesh, + const std::string nameT); + + //- Write the temperature values into the buffer + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); + + //- Read the temperature values from the buffer + void read(double* buffer, const unsigned int dim); + + bool isLocationTypeSupported(const bool meshConnectivity) const override; + + //- Get the name of the current data field + std::string getDataName() const override; +}; + +} +} + +#endif diff --git a/FF/TemperatureGradient.C b/FF/TemperatureGradient.C new file mode 100644 index 00000000..e9384c7a --- /dev/null +++ b/FF/TemperatureGradient.C @@ -0,0 +1,73 @@ +#include "TemperatureGradient.H" +#include "mixedFvPatchFields.H" + +using namespace Foam; + +preciceAdapter::FF::TemperatureGradient::TemperatureGradient( + const Foam::fvMesh& mesh, + const std::string nameT) +: T_( + const_cast( + &mesh.lookupObject(nameT))) +{ + dataType_ = scalar; +} + +std::size_t preciceAdapter::FF::TemperatureGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // Get the Temperature gradient boundary patch + const scalarField gradientPatch((T_->boundaryFieldRef()[patchID]) + .snGrad()); + + // For every cell of the patch + forAll(gradientPatch, i) + { + // Copy the Temperature gradient into the buffer + buffer[bufferIndex++] = + gradientPatch[i]; + } + } + return bufferIndex; +} + +void preciceAdapter::FF::TemperatureGradient::read(double* buffer, const unsigned int dim) +{ + int bufferIndex = 0; + + // For every boundary patch of the interface + for (uint j = 0; j < patchIDs_.size(); j++) + { + int patchID = patchIDs_.at(j); + + // Get the Temperature gradient boundary patch + scalarField& gradientPatch = + refCast( + T_->boundaryFieldRef()[patchID]) + .gradient(); + + // For every cell of the patch + forAll(gradientPatch, i) + { + // Set the Temperature gradient as the buffer value + gradientPatch[i] = + -buffer[bufferIndex++]; + } + } +} + +bool preciceAdapter::FF::TemperatureGradient::isLocationTypeSupported(const bool meshConnectivity) const +{ + return (this->locationType_ == LocationType::faceCenters); +} + +std::string preciceAdapter::FF::TemperatureGradient::getDataName() const +{ + return "TemperatureGradient"; +} diff --git a/FF/TemperatureGradient.H b/FF/TemperatureGradient.H new file mode 100644 index 00000000..c7259a7b --- /dev/null +++ b/FF/TemperatureGradient.H @@ -0,0 +1,42 @@ +#ifndef FF_TEMPERATURE_GRADIENT_H +#define FF_TEMPERATURE_GRADIENT_H + +#include "CouplingDataUser.H" + +#include "fvCFD.H" + +namespace preciceAdapter +{ +namespace FF +{ + +//- Class that writes and reads Temperature gradient +class TemperatureGradient : public CouplingDataUser +{ + +private: + //- Temperature field + Foam::volScalarField* T_; + +public: + //- Constructor + TemperatureGradient( + const Foam::fvMesh& mesh, + const std::string nameT); + + //- Write the Temperature gradient values into the buffer + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); + + //- Read the Temperature gradient values from the buffer + void read(double* buffer, const unsigned int dim); + + bool isLocationTypeSupported(const bool meshConnectivity) const override; + + //- Get the name of the current data field + std::string getDataName() const override; +}; + +} +} + +#endif diff --git a/FF/Velocity.C b/FF/Velocity.C index 747def6f..28092919 100644 --- a/FF/Velocity.C +++ b/FF/Velocity.C @@ -1,73 +1,205 @@ #include "Velocity.H" +#include "coupledVelocityFvPatchField.H" using namespace Foam; preciceAdapter::FF::Velocity::Velocity( const Foam::fvMesh& mesh, - const std::string nameU) + const std::string nameU, + const std::string namePhi, + bool fluxCorrection) : U_( const_cast( - &mesh.lookupObject(nameU))) + &mesh.lookupObject(nameU))), + phi_(const_cast( + &mesh.lookupObject(namePhi))), + fluxCorrection_(fluxCorrection) { + if (mesh.foundObject(nameU)) + { + U_ = const_cast( + &mesh.lookupObject(nameU)); + } + else + { + U_ = new volVectorField( + IOobject( + nameU, + mesh.time().timeName(), + mesh, + IOobject::MUST_READ, + IOobject::AUTO_WRITE), + mesh); + } dataType_ = vector; } -void preciceAdapter::FF::Velocity::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FF::Velocity::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (const auto& cell : U_->internalField()) + { + // x-dimension + buffer[bufferIndex++] = cell.x(); + + // y-dimension + buffer[bufferIndex++] = cell.y(); + + if (dim == 3) + { + // z-dimension + buffer[bufferIndex++] = cell.z(); + } + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(U_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // x-dimension + buffer[bufferIndex++] = U_->internalField()[currentCell].x(); + + // y-dimension + buffer[bufferIndex++] = U_->internalField()[currentCell].y(); + + if (dim == 3) + { + // z-dimension + buffer[bufferIndex++] = U_->internalField()[currentCell].z(); + } + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { int patchID = patchIDs_.at(j); + vectorField UPatch = U_->boundaryField()[patchID]; + + // Correct the velocity by the boundary face flux + if (fluxCorrection_) + { + scalarField phip = phi_->boundaryFieldRef()[patchID]; + vectorField n = U_->boundaryField()[patchID].patch().nf(); + const scalarField& magS = U_->boundaryFieldRef()[patchID].patch().magSf(); + UPatch = UPatch - n * (n & U_->boundaryField()[patchID]) + n * phip / magS; + } + // For every cell of the patch forAll(U_->boundaryFieldRef()[patchID], i) { // Copy the velocity into the buffer // x-dimension buffer[bufferIndex++] = - U_->boundaryFieldRef()[patchID][i].x(); + UPatch[i].x(); // y-dimension buffer[bufferIndex++] = - U_->boundaryFieldRef()[patchID][i].y(); + UPatch[i].y(); if (dim == 3) { // z-dimension buffer[bufferIndex++] = - U_->boundaryFieldRef()[patchID][i].z(); + UPatch[i].z(); } } } + return bufferIndex; } void preciceAdapter::FF::Velocity::read(double* buffer, const unsigned int dim) { int bufferIndex = 0; + if (this->locationType_ == LocationType::volumeCenters) + { + if (cellSetNames_.empty()) + { + for (auto& cell : U_->ref()) + { + // x-dimension + cell.x() = buffer[bufferIndex++]; + + // y-dimension + cell.y() = buffer[bufferIndex++]; + + if (dim == 3) + { + // z-dimension + cell.z() = buffer[bufferIndex++]; + } + } + } + else + { + for (const auto& cellSetName : cellSetNames_) + { + cellSet overlapRegion(U_->mesh(), cellSetName); + const labelList& cells = overlapRegion.toc(); + + for (const auto& currentCell : cells) + { + // x-dimension + U_->ref()[currentCell].x() = buffer[bufferIndex++]; + + // y-dimension + U_->ref()[currentCell].y() = buffer[bufferIndex++]; + + if (dim == 3) + { + // z-dimension + U_->ref()[currentCell].z() = buffer[bufferIndex++]; + } + } + } + } + } + // For every boundary patch of the interface for (uint j = 0; j < patchIDs_.size(); j++) { int patchID = patchIDs_.at(j); + // Get the velocity value boundary patch + vectorField* valuePatchPtr = &U_->boundaryFieldRef()[patchID]; + if (isA(U_->boundaryFieldRef()[patchID])) + { + valuePatchPtr = &refCast( + U_->boundaryFieldRef()[patchID]) + .refValue(); + } + vectorField& valuePatch = *valuePatchPtr; + // For every cell of the patch forAll(U_->boundaryFieldRef()[patchID], i) { // Set the velocity as the buffer value // x-dimension - U_->boundaryFieldRef()[patchID][i].x() = + valuePatch[i].x() = buffer[bufferIndex++]; // y-dimension - U_->boundaryFieldRef()[patchID][i].y() = + valuePatch[i].y() = buffer[bufferIndex++]; if (dim == 3) { // z-dimension - U_->boundaryFieldRef()[patchID][i].z() = + valuePatch[i].z() = buffer[bufferIndex++]; } } @@ -76,7 +208,14 @@ void preciceAdapter::FF::Velocity::read(double* buffer, const unsigned int dim) bool preciceAdapter::FF::Velocity::isLocationTypeSupported(const bool meshConnectivity) const { - return (this->locationType_ == LocationType::faceCenters); + if (meshConnectivity) + { + return (this->locationType_ == LocationType::faceCenters); + } + else + { + return (this->locationType_ == LocationType::faceCenters || this->locationType_ == LocationType::volumeCenters); + } } std::string preciceAdapter::FF::Velocity::getDataName() const diff --git a/FF/Velocity.H b/FF/Velocity.H index 8c5e396b..c6706821 100644 --- a/FF/Velocity.H +++ b/FF/Velocity.H @@ -4,6 +4,7 @@ #include "CouplingDataUser.H" #include "fvCFD.H" +#include "cellSet.H" namespace preciceAdapter { @@ -17,15 +18,21 @@ class Velocity : public CouplingDataUser private: //- Velocity field Foam::volVectorField* U_; + //- Face flux field + Foam::surfaceScalarField* phi_; + //- Correct velocity by face flux + bool fluxCorrection_ = false; public: //- Constructor Velocity( const Foam::fvMesh& mesh, - const std::string nameU); + const std::string nameU, + const std::string namePhi, + bool fluxCorrection = false); //- Write the velocity values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim); + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim); //- Read the velocity values from the buffer void read(double* buffer, const unsigned int dim); diff --git a/FF/VelocityGradient.C b/FF/VelocityGradient.C index 8c100602..90c685a7 100644 --- a/FF/VelocityGradient.C +++ b/FF/VelocityGradient.C @@ -1,4 +1,5 @@ #include "VelocityGradient.H" +#include "coupledVelocityFvPatchField.H" using namespace Foam; @@ -12,7 +13,7 @@ preciceAdapter::FF::VelocityGradient::VelocityGradient( dataType_ = vector; } -void preciceAdapter::FF::VelocityGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FF::VelocityGradient::write(double* buffer, bool meshConnectivity, const unsigned int dim) { int bufferIndex = 0; @@ -45,6 +46,7 @@ void preciceAdapter::FF::VelocityGradient::write(double* buffer, bool meshConnec } } } + return bufferIndex; } void preciceAdapter::FF::VelocityGradient::read(double* buffer, const unsigned int dim) @@ -57,10 +59,21 @@ void preciceAdapter::FF::VelocityGradient::read(double* buffer, const unsigned i int patchID = patchIDs_.at(j); // Get the velocity gradient boundary patch - vectorField& gradientPatch = - refCast( - U_->boundaryFieldRef()[patchID]) - .gradient(); + vectorField* gradientPatchPtr; + if (isA(U_->boundaryFieldRef()[patchID])) + { + gradientPatchPtr = &refCast( + U_->boundaryFieldRef()[patchID]) + .refGrad(); + } + else + { + gradientPatchPtr = &refCast( + U_->boundaryFieldRef()[patchID]) + .gradient(); + } + vectorField& gradientPatch = *gradientPatchPtr; + // For every cell of the patch forAll(gradientPatch, i) diff --git a/FF/VelocityGradient.H b/FF/VelocityGradient.H index 3e1f16da..77430aeb 100644 --- a/FF/VelocityGradient.H +++ b/FF/VelocityGradient.H @@ -25,7 +25,7 @@ public: const std::string nameU); //- Write the velocity gradient values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the velocity gradient values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/FSI/Displacement.C b/FSI/Displacement.C index 69baf676..4a76e26f 100644 --- a/FSI/Displacement.C +++ b/FSI/Displacement.C @@ -36,7 +36,7 @@ void preciceAdapter::FSI::Displacement::initialize() } -void preciceAdapter::FSI::Displacement::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FSI::Displacement::write(double* buffer, bool meshConnectivity, const unsigned int dim) { /* TODO: Implement * We need two nested for-loops for each patch, @@ -46,9 +46,9 @@ void preciceAdapter::FSI::Displacement::write(double* buffer, bool meshConnectiv // Copy the displacement field from OpenFOAM to the buffer + int bufferIndex = 0; if (this->locationType_ == LocationType::faceCenters) { - int bufferIndex = 0; // For every boundary patch of the interface for (const label patchID : patchIDs_) { @@ -70,7 +70,6 @@ void preciceAdapter::FSI::Displacement::write(double* buffer, bool meshConnectiv "See https://github.com/precice/openfoam-adapter/issues/153.", "warning")); - int bufferIndex = 0; // For every boundary patch of the interface for (const label patchID : patchIDs_) { @@ -87,6 +86,7 @@ void preciceAdapter::FSI::Displacement::write(double* buffer, bool meshConnectiv } } } + return bufferIndex; } diff --git a/FSI/Displacement.H b/FSI/Displacement.H index 8b7d5216..4339a29b 100644 --- a/FSI/Displacement.H +++ b/FSI/Displacement.H @@ -36,7 +36,7 @@ public: const std::string nameCellDisplacement); //- Write the displacement values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the displacement values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/FSI/DisplacementDelta.C b/FSI/DisplacementDelta.C index 19c93139..a4bdd730 100644 --- a/FSI/DisplacementDelta.C +++ b/FSI/DisplacementDelta.C @@ -34,7 +34,7 @@ void preciceAdapter::FSI::DisplacementDelta::initialize() } -void preciceAdapter::FSI::DisplacementDelta::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FSI::DisplacementDelta::write(double* buffer, bool meshConnectivity, const unsigned int dim) { /* TODO: Implement * We need two nested for-loops for each patch, @@ -44,6 +44,7 @@ void preciceAdapter::FSI::DisplacementDelta::write(double* buffer, bool meshConn FatalErrorInFunction << "Writing displacementDeltas is not supported." << exit(FatalError); + return 0; } // return the displacement to use later in the velocity? diff --git a/FSI/DisplacementDelta.H b/FSI/DisplacementDelta.H index 27c57e51..65066b77 100644 --- a/FSI/DisplacementDelta.H +++ b/FSI/DisplacementDelta.H @@ -36,7 +36,7 @@ public: const std::string nameCellDisplacement); //- Write the displacementDelta values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the displacementDelta values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/FSI/Force.C b/FSI/Force.C index a1ab6651..d8cbad39 100644 --- a/FSI/Force.C +++ b/FSI/Force.C @@ -36,9 +36,9 @@ preciceAdapter::FSI::Force::Force( } } -void preciceAdapter::FSI::Force::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FSI::Force::write(double* buffer, bool meshConnectivity, const unsigned int dim) { - this->writeToBuffer(buffer, *Force_, dim); + return this->writeToBuffer(buffer, *Force_, dim); } void preciceAdapter::FSI::Force::read(double* buffer, const unsigned int dim) diff --git a/FSI/Force.H b/FSI/Force.H index c528b14d..9e763c10 100644 --- a/FSI/Force.H +++ b/FSI/Force.H @@ -26,7 +26,7 @@ public: const std::string nameForce); //- Write the forces values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the forces values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/FSI/ForceBase.C b/FSI/ForceBase.C index 4e9168b0..48297cdf 100644 --- a/FSI/ForceBase.C +++ b/FSI/ForceBase.C @@ -130,9 +130,9 @@ Foam::tmp preciceAdapter::FSI::ForceBase::mu() const } } -void preciceAdapter::FSI::ForceBase::writeToBuffer(double* buffer, - volVectorField& forceField, - const unsigned int dim) const +std::size_t preciceAdapter::FSI::ForceBase::writeToBuffer(double* buffer, + volVectorField& forceField, + const unsigned int dim) const { // Compute forces. See the Forces function object. // Stress tensor boundary field @@ -188,6 +188,7 @@ void preciceAdapter::FSI::ForceBase::writeToBuffer(double* buffer, forceField.boundaryField()[patchID][i][d]; } } + return bufferIndex; } void preciceAdapter::FSI::ForceBase::readFromBuffer(double* buffer) const diff --git a/FSI/ForceBase.H b/FSI/ForceBase.H index 38643333..2c53086a 100644 --- a/FSI/ForceBase.H +++ b/FSI/ForceBase.H @@ -39,9 +39,9 @@ public: const Foam::fvMesh& mesh, const std::string solverType); - void writeToBuffer(double* buffer, - Foam::volVectorField& forceField, - const unsigned int dim) const; + std::size_t writeToBuffer(double* buffer, + Foam::volVectorField& forceField, + const unsigned int dim) const; void readFromBuffer(double* buffer) const; diff --git a/FSI/ModuleFSI.C b/FSI/ModuleFSI.C new file mode 100644 index 00000000..0eccb26b --- /dev/null +++ b/FSI/ModuleFSI.C @@ -0,0 +1,7 @@ +// Central inlude file to reduce the number of build targets and build time +#include "FSI.C" +#include "ForceBase.C" +#include "Force.C" +#include "Stress.C" +#include "Displacement.C" +#include "DisplacementDelta.C" diff --git a/FSI/Stress.C b/FSI/Stress.C index c5ba6d10..1194a249 100644 --- a/FSI/Stress.C +++ b/FSI/Stress.C @@ -21,9 +21,9 @@ preciceAdapter::FSI::Stress::Stress( Foam::vector::zero)); } -void preciceAdapter::FSI::Stress::write(double* buffer, bool meshConnectivity, const unsigned int dim) +std::size_t preciceAdapter::FSI::Stress::write(double* buffer, bool meshConnectivity, const unsigned int dim) { - this->writeToBuffer(buffer, *Stress_, dim); + return this->writeToBuffer(buffer, *Stress_, dim); } void preciceAdapter::FSI::Stress::read(double* buffer, const unsigned int dim) diff --git a/FSI/Stress.H b/FSI/Stress.H index 24f62034..331100b4 100644 --- a/FSI/Stress.H +++ b/FSI/Stress.H @@ -27,7 +27,7 @@ public: const std::string solverType); //- Write the stress values into the buffer - void write(double* buffer, bool meshConnectivity, const unsigned int dim) final; + std::size_t write(double* buffer, bool meshConnectivity, const unsigned int dim) final; //- Read the stress values from the buffer void read(double* buffer, const unsigned int dim) final; diff --git a/Interface.C b/Interface.C index 694f2b54..55d59c53 100644 --- a/Interface.C +++ b/Interface.C @@ -1,16 +1,18 @@ #include "Interface.H" #include "Utilities.H" #include "faceTriangulation.H" +#include "cellSet.H" using namespace Foam; preciceAdapter::Interface::Interface( - precice::SolverInterface& precice, + precice::Participant& precice, const fvMesh& mesh, std::string meshName, std::string locationsType, std::vector patchNames, + std::vector cellSetNames, bool meshConnectivity, bool restartFromDeformed, const std::string& namePointDisplacement, @@ -18,13 +20,11 @@ preciceAdapter::Interface::Interface( : precice_(precice), meshName_(meshName), patchNames_(patchNames), + cellSetNames_(cellSetNames), meshConnectivity_(meshConnectivity), restartFromDeformed_(restartFromDeformed) { - // Get the meshID from preCICE - meshID_ = precice_.getMeshID(meshName_); - - dim_ = precice_.getDimensions(); + dim_ = precice_.getMeshDimensions(meshName); if (dim_ == 2 && meshConnectivity_ == true) { @@ -42,6 +42,10 @@ preciceAdapter::Interface::Interface( { locationType_ = LocationType::faceNodes; } + else if (locationsType == "volumeCenters" || locationsType == "volumeCentres") + { + locationType_ = LocationType::volumeCenters; + } else { adapterInfo("Interface points location type \"" @@ -100,11 +104,11 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str // Array of the mesh vertices. // One mesh is used for all the patches and each vertex has 3D coordinates. - double vertices[dim_ * numDataLocations_]; + std::vector vertices(dim_ * numDataLocations_); // Array of the indices of the mesh vertices. // Each vertex has one index, but three coordinates. - vertexIDs_ = new int[numDataLocations_]; + vertexIDs_.resize(numDataLocations_); // Initialize the index of the vertices array int verticesIndex = 0; @@ -181,7 +185,7 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str } // Pass the mesh vertices information to preCICE - precice_.setMeshVertices(meshID_, numDataLocations_, vertices, vertexIDs_); + precice_.setMeshVertices(meshName_, vertices, vertexIDs_); } else if (locationType_ == LocationType::faceNodes) { @@ -201,15 +205,18 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str // Array of the mesh vertices. // One mesh is used for all the patches and each vertex has 3D coordinates. - double vertices[dim_ * numDataLocations_]; + std::vector vertices(dim_ * numDataLocations_); // Array of the indices of the mesh vertices. // Each vertex has one index, but three coordinates. - vertexIDs_ = new int[numDataLocations_]; + vertexIDs_.resize(numDataLocations_); // Initialize the index of the vertices array int verticesIndex = 0; + // Map between OpenFOAM vertices and preCICE vertex IDs + std::map, int> verticesMap; + // Get the locations of the mesh vertices (here: face nodes) // for all the patches for (uint j = 0; j < patchIDs_.size(); j++) @@ -237,17 +244,24 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str // Assign the (x,y,z) locations to the vertices // TODO: Ensure consistent order when writing/reading for (int i = 0; i < faceNodes.size(); i++) + { for (unsigned int d = 0; d < dim_; ++d) + { vertices[verticesIndex++] = faceNodes[i][d]; + } + } } // Pass the mesh vertices information to preCICE - precice_.setMeshVertices(meshID_, numDataLocations_, vertices, vertexIDs_); + precice_.setMeshVertices(meshName_, vertices, vertexIDs_); - // meshConnectivity for prototype neglected - // Only set the triangles, if necessary if (meshConnectivity_) { + for (std::size_t i = 0; i < vertexIDs_.size(); ++i) + { + verticesMap.emplace(std::make_tuple(vertices[3 * i], vertices[3 * i + 1], vertices[3 * i + 2]), vertexIDs_[i]); + } + for (uint j = 0; j < patchIDs_.size(); j++) { // Define triangles @@ -266,7 +280,6 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str // Define constants const int triaPerQuad = 2; const int nodesPerTria = 3; - const int componentsPerNode = 3; // Get the list of faces and coordinates at the interface patch const List faceField = mesh.boundaryMesh()[patchIDs_.at(j)].localFaces(); @@ -280,43 +293,140 @@ void preciceAdapter::Interface::configureMesh(const fvMesh& mesh, const std::str pointCoords -= resetField; } - // Array to store coordinates in preCICE format - double triCoords[faceField.size() * triaPerQuad * nodesPerTria * componentsPerNode]; - - unsigned int coordIndex = 0; + //Array to store the IDs we get from preCICE + std::vector triVertIDs; + triVertIDs.reserve(faceField.size() * triaPerQuad * nodesPerTria); - // Iterate over faces + // Triangulate all faces and collect set of nodes that form triangles, + // which are used to set mesh triangles in preCICE. forAll(faceField, facei) { const face& faceQuad = faceField[facei]; + // Triangulate the face faceTriangulation faceTri(pointCoords, faceQuad, false); + // Iterate over all triangles generated out of each (quad) face for (uint triIndex = 0; triIndex < triaPerQuad; triIndex++) { + // Get the vertex that corresponds to the x,y,z coordinates of each node of a triangle for (uint nodeIndex = 0; nodeIndex < nodesPerTria; nodeIndex++) { - for (uint xyz = 0; xyz < componentsPerNode; xyz++) - triCoords[coordIndex++] = pointCoords[faceTri[triIndex][nodeIndex]][xyz]; + triVertIDs.push_back(verticesMap.at(std::make_tuple(pointCoords[faceTri[triIndex][nodeIndex]][0], pointCoords[faceTri[triIndex][nodeIndex]][1], pointCoords[faceTri[triIndex][nodeIndex]][2]))); } } } - //Array to store the IDs we get from preCICE - int triVertIDs[faceField.size() * (triaPerQuad * nodesPerTria)]; - - //Get preCICE IDs - precice_.getMeshVertexIDsFromPositions(meshID_, faceField.size() * (triaPerQuad * nodesPerTria), triCoords, triVertIDs); - DEBUG(adapterInfo("Number of triangles: " + std::to_string(faceField.size() * triaPerQuad))); //Set Triangles - for (int facei = 0; facei < faceField.size() * triaPerQuad; facei++) + precice_.setMeshTriangles(meshName_, triVertIDs); + } + } + } + else if (locationType_ == LocationType::volumeCenters) + { + // The volume coupling implementation considers the mesh points in the volume and + // on the boundary patches in order to take the boundary conditions into account + + // Get the cell labels of the overlapping region + std::vector overlapCells; + + if (!cellSetNames_.empty()) + { + // For every cellSet that participates in the coupling + for (uint j = 0; j < cellSetNames_.size(); j++) + { + // Create a cell set + cellSet overlapRegion(mesh, cellSetNames_[j]); + + // Add the cells IDs to the vector and count how many overlap cells the interface has + overlapCells.push_back(overlapRegion.toc()); + numDataLocations_ += overlapCells[j].size(); + } + } + else + { + numDataLocations_ = mesh.C().size(); + } + + // Count the data locations for all the patches + // and add those to the previously determined number of mesh points in the volume + for (uint j = 0; j < patchIDs_.size(); j++) + { + numDataLocations_ += + mesh.boundaryMesh()[patchIDs_.at(j)].faceCentres().size(); + } + DEBUG(adapterInfo("Number of coupling volumes: " + std::to_string(numDataLocations_))); + + // Array of the mesh vertices. + // One mesh is used for all the patches and each vertex has 3D coordinates. + std::vector vertices(dim_ * numDataLocations_); + + // Array of the indices of the mesh vertices. + // Each vertex has one index, but three coordinates. + vertexIDs_.resize(numDataLocations_); + + // Initialize the index of the vertices array + int verticesIndex = 0; + + if (!cellSetNames_.empty()) + { + // for all the overlapping cells (cellSets) + for (uint j = 0; j < cellSetNames_.size(); j++) + { + // Get the cell centres of the current cellSet. + const labelList& cells = overlapCells.at(j); + + // Get the coordinates of the cells of the current cellSet. + for (int i = 0; i < cells.size(); i++) + { + vertices[verticesIndex++] = mesh.C().internalField()[cells[i]].x(); + vertices[verticesIndex++] = mesh.C().internalField()[cells[i]].y(); + if (dim_ == 3) + { + vertices[verticesIndex++] = mesh.C().internalField()[cells[i]].z(); + } + } + } + } + else + { + const vectorField& CellCenters = mesh.C(); + + for (int i = 0; i < CellCenters.size(); i++) + { + vertices[verticesIndex++] = CellCenters[i].x(); + vertices[verticesIndex++] = CellCenters[i].y(); + if (dim_ == 3) + { + vertices[verticesIndex++] = CellCenters[i].z(); + } + } + } + + // Get the locations of the mesh vertices (here: face centers) + // for all the patches + for (uint j = 0; j < patchIDs_.size(); j++) + { + // Get the face centers of the current patch + const vectorField faceCenters = + mesh.boundaryMesh()[patchIDs_.at(j)].faceCentres(); + + // Assign the (x,y,z) locations to the vertices + for (int i = 0; i < faceCenters.size(); i++) + { + vertices[verticesIndex++] = faceCenters[i].x(); + vertices[verticesIndex++] = faceCenters[i].y(); + if (dim_ == 3) { - precice_.setMeshTriangleWithEdges(meshID_, triVertIDs[facei * nodesPerTria], triVertIDs[facei * nodesPerTria + 1], triVertIDs[facei * nodesPerTria + 2]); + vertices[verticesIndex++] = faceCenters[i].z(); } } } + + // Pass the mesh vertices information to preCICE + precice_.setMeshVertices(meshName_, vertices, vertexIDs_); } } @@ -325,12 +435,15 @@ void preciceAdapter::Interface::addCouplingDataWriter( std::string dataName, CouplingDataUser* couplingDataWriter) { - // Set the dataID (from preCICE) - couplingDataWriter->setDataID(precice_.getDataID(dataName, meshID_)); + // Set the data name (from preCICE) + couplingDataWriter->setDataName(dataName); // Set the patchIDs of the patches that form the interface couplingDataWriter->setPatchIDs(patchIDs_); + // Set the names of the cell sets to be coupled (for volume coupling) + couplingDataWriter->setCellSetNames(cellSetNames_); + // Set the location type in the CouplingDataUser class couplingDataWriter->setLocationsType(locationType_); @@ -350,7 +463,7 @@ void preciceAdapter::Interface::addCouplingDataReader( preciceAdapter::CouplingDataUser* couplingDataReader) { // Set the patchIDs of the patches that form the interface - couplingDataReader->setDataID(precice_.getDataID(dataName, meshID_)); + couplingDataReader->setDataName(dataName); // Add the CouplingDataUser to the list of readers couplingDataReader->setPatchIDs(patchIDs_); @@ -358,6 +471,9 @@ void preciceAdapter::Interface::addCouplingDataReader( // Set the location type in the CouplingDataUser class couplingDataReader->setLocationsType(locationType_); + // Set the names of the cell sets to be coupled (for volume coupling) + couplingDataReader->setCellSetNames(cellSetNames_); + // Check, if the current location type is supported by the data type couplingDataReader->checkDataLocation(meshConnectivity_); @@ -409,10 +525,10 @@ void preciceAdapter::Interface::createBuffer() // scalar and vector coupling data users in an interface. With the current // preCICE implementation, it should work as, when writing scalars, // it should only use the first 1/3 elements of the buffer. - dataBuffer_ = new double[dataBufferSize](); + dataBuffer_.resize(dataBufferSize); } -void preciceAdapter::Interface::readCouplingData() +void preciceAdapter::Interface::readCouplingData(double relativeReadTime) { // Make every coupling data reader read for (uint i = 0; i < couplingDataReaders_.size(); i++) @@ -423,25 +539,19 @@ void preciceAdapter::Interface::readCouplingData() // Make preCICE read vector or scalar data // and fill the adapter's buffer - if (couplingDataReader->hasVectorData()) - { - precice_.readBlockVectorData( - couplingDataReader->dataID(), - numDataLocations_, - vertexIDs_, - dataBuffer_); - } - else - { - precice_.readBlockScalarData( - couplingDataReader->dataID(), - numDataLocations_, - vertexIDs_, - dataBuffer_); - } + std::size_t nReadData = vertexIDs_.size() * precice_.getDataDimensions(meshName_, couplingDataReader->dataName()); + // We could add a sanity check here + // nReadData == vertexIDs_.size() * (1 + (dim_ - 1) * static_cast(couplingDataReader->hasVectorData())); + + precice_.readData( + meshName_, + couplingDataReader->dataName(), + vertexIDs_, + relativeReadTime, + {dataBuffer_.data(), nReadData}); // Read the received data from the buffer - couplingDataReader->read(dataBuffer_, dim_); + couplingDataReader->read(dataBuffer_.data(), dim_); } } @@ -459,25 +569,14 @@ void preciceAdapter::Interface::writeCouplingData() couplingDataWriter = couplingDataWriters_.at(i); // Write the data into the adapter's buffer - couplingDataWriter->write(dataBuffer_, meshConnectivity_, dim_); + auto nWrittenData = couplingDataWriter->write(dataBuffer_.data(), meshConnectivity_, dim_); // Make preCICE write vector or scalar data - if (couplingDataWriter->hasVectorData()) - { - precice_.writeBlockVectorData( - couplingDataWriter->dataID(), - numDataLocations_, - vertexIDs_, - dataBuffer_); - } - else - { - precice_.writeBlockScalarData( - couplingDataWriter->dataID(), - numDataLocations_, - vertexIDs_, - dataBuffer_); - } + precice_.writeData( + meshName_, + couplingDataWriter->dataName(), + vertexIDs_, + {dataBuffer_.data(), nWrittenData}); } // } } @@ -497,10 +596,4 @@ preciceAdapter::Interface::~Interface() delete couplingDataWriters_.at(i); } couplingDataWriters_.clear(); - - // Delete the vertexIDs_ - delete[] vertexIDs_; - - // Delete the shared data buffer - delete[] dataBuffer_; } diff --git a/Interface.H b/Interface.H index 3d05329e..885ec9b0 100644 --- a/Interface.H +++ b/Interface.H @@ -5,7 +5,7 @@ #include #include "fvCFD.H" #include "CouplingDataUser.H" -#include "precice/SolverInterface.hpp" +#include #include "pointPatchField.H" @@ -16,7 +16,7 @@ class Interface { protected: //- preCICE solver interface - precice::SolverInterface& precice_; + precice::Participant& precice_; //- Mesh name used in the preCICE configuration std::string meshName_; @@ -33,14 +33,17 @@ protected: //- OpenFOAM patches that form the interface std::vector patchIDs_; + //- Names of the OpenFOAM cell sets to be coupled (for volume coupling) + std::vector cellSetNames_; + //- Number of data points (cell centers) on the interface int numDataLocations_ = 0; //- Vertex IDs assigned by preCICE - int* vertexIDs_; + std::vector vertexIDs_; //- Buffer for the coupling data - double* dataBuffer_; + std::vector dataBuffer_; //- Vector of CouplingDataReaders std::vector couplingDataReaders_; @@ -66,11 +69,12 @@ protected: public: //- Constructor Interface( - precice::SolverInterface& precice, + precice::Participant& precice, const Foam::fvMesh& mesh, std::string meshName, std::string locationsType, std::vector patchNames, + std::vector cellSetNames, bool meshConnectivity, bool restartFromDeformed, const std::string& namePointDisplacement, @@ -94,7 +98,7 @@ public: //- Call read() on each registered couplingDataReader to read the coupling // data from the buffer and apply the boundary conditions - void readCouplingData(); + void readCouplingData(double relativeReadTime); //- Call write() on each registered couplingDataWriter to extract the boundary // data and write them into the buffer diff --git a/Make/files b/Make/files index adf8dd18..6fae86ae 100644 --- a/Make/files +++ b/Make/files @@ -4,26 +4,9 @@ Interface.C CouplingDataUser.C -CHT/Temperature.C -CHT/KappaEffective.C -CHT/HeatFlux.C -CHT/HeatTransferCoefficient.C -CHT/SinkTemperature.C - -CHT/CHT.C - -FSI/FSI.C -FSI/ForceBase.C -FSI/Force.C -FSI/Stress.C -FSI/Displacement.C -FSI/DisplacementDelta.C - -FF/FF.C -FF/Velocity.C -FF/VelocityGradient.C -FF/Pressure.C -FF/PressureGradient.C +CHT/ModuleCHT.C +FSI/ModuleFSI.C +FF/ModuleFF.C Adapter.C diff --git a/README.md b/README.md index c9a186a0..b4578250 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,17 @@ # OpenFOAM-preCICE adapter -[![Build with OpenFOAM v2212](https://github.com/precice/openfoam-adapter/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/precice/openfoam-adapter/actions/workflows/build.yml) +[![Ask questions in the forum](https://img.shields.io/badge/community-discourse_forum-orange?link=https%3A%2F%2Fprecice.discourse.group%2F)](https://precice.discourse.group/) +[![Build with OpenFOAM v2312](https://github.com/precice/openfoam-adapter/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/precice/openfoam-adapter/actions/workflows/build.yml) [![Changelog](https://img.shields.io/badge/Keep%20a%20Changelog--555.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmMTVkMzAiIHZpZXdCb3g9IjAgMCAxODcgMTg1Ij48cGF0aCBkPSJNNjIgN2MtMTUgMy0yOCAxMC0zNyAyMmExMjIgMTIyIDAgMDAtMTggOTEgNzQgNzQgMCAwMDE2IDM4YzYgOSAxNCAxNSAyNCAxOGE4OSA4OSAwIDAwMjQgNCA0NSA0NSAwIDAwNiAwbDMtMSAxMy0xYTE1OCAxNTggMCAwMDU1LTE3IDYzIDYzIDAgMDAzNS01MiAzNCAzNCAwIDAwLTEtNWMtMy0xOC05LTMzLTE5LTQ3LTEyLTE3LTI0LTI4LTM4LTM3QTg1IDg1IDAgMDA2MiA3em0zMCA4YzIwIDQgMzggMTQgNTMgMzEgMTcgMTggMjYgMzcgMjkgNTh2MTJjLTMgMTctMTMgMzAtMjggMzhhMTU1IDE1NSAwIDAxLTUzIDE2bC0xMyAyaC0xYTUxIDUxIDAgMDEtMTItMWwtMTctMmMtMTMtNC0yMy0xMi0yOS0yNy01LTEyLTgtMjQtOC0zOWExMzMgMTMzIDAgMDE4LTUwYzUtMTMgMTEtMjYgMjYtMzMgMTQtNyAyOS05IDQ1LTV6TTQwIDQ1YTk0IDk0IDAgMDAtMTcgNTQgNzUgNzUgMCAwMDYgMzJjOCAxOSAyMiAzMSA0MiAzMiAyMSAyIDQxLTIgNjAtMTRhNjAgNjAgMCAwMDIxLTE5IDUzIDUzIDAgMDA5LTI5YzAtMTYtOC0zMy0yMy01MWE0NyA0NyAwIDAwLTUtNWMtMjMtMjAtNDUtMjYtNjctMTgtMTIgNC0yMCA5LTI2IDE4em0xMDggNzZhNTAgNTAgMCAwMS0yMSAyMmMtMTcgOS0zMiAxMy00OCAxMy0xMSAwLTIxLTMtMzAtOS01LTMtOS05LTEzLTE2YTgxIDgxIDAgMDEtNi0zMiA5NCA5NCAwIDAxOC0zNSA5MCA5MCAwIDAxNi0xMmwxLTJjNS05IDEzLTEzIDIzLTE2IDE2LTUgMzItMyA1MCA5IDEzIDggMjMgMjAgMzAgMzYgNyAxNSA3IDI5IDAgNDJ6bS00My03M2MtMTctOC0zMy02LTQ2IDUtMTAgOC0xNiAyMC0xOSAzN2E1NCA1NCAwIDAwNSAzNGM3IDE1IDIwIDIzIDM3IDIyIDIyLTEgMzgtOSA0OC0yNGE0MSA0MSAwIDAwOC0yNCA0MyA0MyAwIDAwLTEtMTJjLTYtMTgtMTYtMzEtMzItMzh6bS0yMyA5MWgtMWMtNyAwLTE0LTItMjEtN2EyNyAyNyAwIDAxLTEwLTEzIDU3IDU3IDAgMDEtNC0yMCA2MyA2MyAwIDAxNi0yNWM1LTEyIDEyLTE5IDI0LTIxIDktMyAxOC0yIDI3IDIgMTQgNiAyMyAxOCAyNyAzM3MtMiAzMS0xNiA0MGMtMTEgOC0yMSAxMS0zMiAxMXptMS0zNHYxNGgtOFY2OGg4djI4bDEwLTEwaDExbC0xNCAxNSAxNyAxOEg5NnoiLz48L3N2Zz4K)](https://github.com/precice/openfoam-adapter/blob/develop/CHANGELOG.md) - - GNU GPL license - - +[![License](https://img.shields.io/github/license/precice/openfoam-adapter.svg)](https://github.com/precice/openfoam-adapter/blob/master/LICENSE) ## Start here See the [adapter documentation](https://precice.org/adapter-openfoam-overview.html) and related [tutorials](https://precice.org/tutorials.html). -Please [report any issues](https://github.com/precice/openfoam-adapter/issues) here and give us feedback through [one of our community channels](https://precice.org/community-channels.html). +Please [report any issues](https://github.com/precice/openfoam-adapter/issues) here and give us feedback through [one of our community channels](https://precice.org/community-channels.html). Please ask question in the [preCICE forum](https://precice.discourse.group/), not via issues. + +This project is actively maintained on [precice/openfoam-adapter](https://github.com/precice/openfoam-adapter). Current maintainers: [@MakisH](https://github.com/MakisH/) and [@DavidSCN](https://github.com/DavidSCN). ## Contributing @@ -21,26 +19,13 @@ We welcome contributions! Have a look at open [good first issues](https://github Check the file `CONTRIBUTING.md` for a few tips and guidelines. -## History - -This project is actively maintained on [precice/openfoam-adapter](https://github.com/precice/openfoam-adapter). Current maintainers: [@MakisH](https://github.com/MakisH/) and [@DavidSCN](https://github.com/DavidSCN). - -This adapter was developed as part of [Gerasimos Chourdakis' master's thesis](https://mediatum.ub.tum.de/1462269) [1]. -It is based on [previous work](https://github.com/ludcila/CHT-preCICE) by Lucia Cheung ([master's thesis](https://www5.in.tum.de/pub/Cheung2016_Thesis.pdf) [2], in cooperation with [SimScale](https://www.simscale.com/)). +## Citing -The fluid-structure interaction module was developed in close collaboration between Gerasimos Chourdakis and Derek Risseeuw (TU Delft), in the context of the [master's thesis of the latter](http://resolver.tudelft.nl/uuid:70beddde-e870-4c62-9a2f-8758b4e49123) [3]. We would also like to thank David Schneider (Univ. Siegen / TUM) and Maximilian Müller (TU Braunschweig) for sharing the code and experience of their similar previous work. - -The fluid-fluid coupling module was added by Gerasimos Chourdakis, in the context of his dissertation. [#67](https://github.com/precice/openfoam-adapter/pull/67) - -The adapter is [easily extensible](https://precice.org/adapter-openfoam-extend.html). +Whenever using or referring to this adapter in academic publications, please cite it [1]. See the option "Cite this repository" in the "About" section, as well as the [preCICE literature guide](https://precice.org/fundamentals-literature-guide.html) and the [adapter overview page](https://precice.org/adapter-openfoam-overview.html) for more information. ## References -[1] Gerasimos Chourdakis. A general OpenFOAM adapter for the coupling library preCICE. Master's thesis, Department of Informatics, Technical University of Munich, 2017. - -[2] Lucia Cheung Yau. Conjugate heat transfer with the multiphysics coupling library preCICE. Master’s thesis, Department of Informatics, Technical University of Munich, 2016. - -[3] Derek Risseeuw. Fluid Structure Interaction Modelling of Flapping Wings. Master's thesis, Faculty of Aerospace Engineering, Delft University of Technology, 2019. +[1] Chourdakis, G., Schneider, D., & Uekermann, B. (2023). OpenFOAM-preCICE: Coupling OpenFOAM with External Solvers for Multi-Physics Simulations. OpenFOAM® Journal, 3, 1–25. [DOI: 10.51560/ofj.v3.88](https://doi.org/10.51560/ofj.v3.88) ## Disclaimer diff --git a/docs/README.md b/docs/README.md index a1a437c5..cb5e6671 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,13 +8,14 @@ summary: An OpenFOAM function object for CHT, FSI, and fluid-fluid coupled simul ## What is this? -This preCICE adapter is a plug-in (function object) for OpenFOAM, which can work with any recent version of OpenFOAM (.com / .org, see [supported OpenFOAM versions](https://precice.org/adapter-openfoam-support.html)). It supports fluid-structure interaction (fluid part), conjugate heat transfer (fluid and solid parts), and fluid-fluid simulations, while it is also easily extensible. +This preCICE adapter is a plug-in (function object) for OpenFOAM, which can work with any recent version of OpenFOAM (.com / .org, see [supported OpenFOAM versions](https://precice.org/adapter-openfoam-support.html)). It supports fluid-structure interaction (fluid part), conjugate heat transfer (fluid and solid parts), and fluid-fluid simulations, while it is also easily extensible. Besides surface coupling, the adapter also supports volume coupling (overlapping domains). ## What can it do? -This adapter can read/write the following fields: +This adapter can read/write the following fields in a surface coupling setup: - Temperature (read + write) +- Temperature gradient (read + write) - Heat flux (read + write) - Sink temperature (read + write) - Heat transfer coefficient (read + write) @@ -26,6 +27,15 @@ This adapter can read/write the following fields: - Pressure gradient (read + write) - Velocity (read + write) - Velocity gradient (read + write) +- Phase fraction (alpha) (read + write) +- Phase fraction (alpha) gradient (read + write) +- Phase flux (phi) (read + write) + +In addition, the adapter supports the following fields in a volume coupling setup: + +- Temperature (write) +- Pressure (write) +- Velocity (read + write) All features of preCICE are supported, including implicit coupling and nearest-projection mapping. Even though OpenFOAM is 3D, this adapter can also work in the 2D mode of preCICE, defining only one layer of interface nodes (automatically). @@ -43,21 +53,30 @@ our [training session from the 15th OpenFOAM Workshop](https://mediatum.ub.tum.d ## Cite -We are currently working on an up-to-date reference paper. Until then, please cite this adapter using [1]: +Please cite this adapter using our [reference paper in the OpenFOAM Journal](https://doi.org/10.51560/ofj.v3.88) [1]. See the [preCICE literature guide](https://precice.org/fundamentals-literature-guide.html) for more details. + +## History -```text -Gerasimos Chourdakis. A general OpenFOAM adapter for the coupling library preCICE. Master's thesis, Department of Informatics, Technical University of Munich, 2017. -``` +This project is actively maintained on [precice/openfoam-adapter](https://github.com/precice/openfoam-adapter). Current maintainers: [@MakisH](https://github.com/MakisH/) and [@DavidSCN](https://github.com/DavidSCN). -For CHT-specific topics, you may want to additionally look into [2] and for FSI into [3]. +This adapter was developed as part of [Gerasimos Chourdakis' master's thesis](https://mediatum.ub.tum.de/1462269) [2]. +It is based on [previous work](https://github.com/ludcila/CHT-preCICE) by Lucia Cheung ([master's thesis](https://www5.in.tum.de/pub/Cheung2016_Thesis.pdf) [3], in cooperation with [SimScale](https://www.simscale.com/)). + +The fluid-structure interaction module was developed in close collaboration between Gerasimos Chourdakis and Derek Risseeuw (TU Delft), in the context of the [master's thesis of the latter](http://resolver.tudelft.nl/uuid:70beddde-e870-4c62-9a2f-8758b4e49123) [4]. We would also like to thank David Schneider (Univ. Siegen / TUM) and Maximilian Müller (TU Braunschweig) for sharing the code and experience of their similar previous work. + +The fluid-fluid coupling module was added by Gerasimos Chourdakis, in the context of his dissertation. [#67](https://github.com/precice/openfoam-adapter/pull/67) + +The adapter is [easily extensible](https://precice.org/adapter-openfoam-extend.html). ### Related literature -[1] Gerasimos Chourdakis. [A general OpenFOAM adapter for the coupling library preCICE](https://mediatum.ub.tum.de/1462269). Master's thesis, Department of Informatics, Technical University of Munich, 2017. +[1] Chourdakis, G., Schneider, D., & Uekermann, B. (2023). OpenFOAM-preCICE: Coupling OpenFOAM with External Solvers for Multi-Physics Simulations. OpenFOAM® Journal, 3, 1–25. [DOI: 10.51560/ofj.v3.88](https://doi.org/10.51560/ofj.v3.88) + +[2] Gerasimos Chourdakis. A general OpenFOAM adapter for the coupling library preCICE. Master's thesis, Department of Informatics, Technical University of Munich, 2017. -[2] Lucia Cheung Yau. [Conjugate heat transfer with the multiphysics coupling library preCICE](http://www5.in.tum.de/pub/Cheung2016_Thesis.pdf). Master’s thesis, Department of Informatics, Technical University of Munich, 2016. +[3] Lucia Cheung Yau. Conjugate heat transfer with the multiphysics coupling library preCICE. Master’s thesis, Department of Informatics, Technical University of Munich, 2016. -[3] Derek Risseeuw. [Fluid Structure Interaction Modelling of Flapping Wings](https://repository.tudelft.nl/islandora/object/uuid:70beddde-e870-4c62-9a2f-8758b4e49123). Master's thesis, Faculty of Aerospace Engineering, Delft University of Technology, 2019. +[4] Derek Risseeuw. Fluid Structure Interaction Modelling of Flapping Wings. Master's thesis, Faculty of Aerospace Engineering, Delft University of Technology, 2019. {% disclaimer %} This offering is not approved or endorsed by OpenCFD Limited, producer and distributor of the OpenFOAM software via www.openfoam.com, and owner of the OPENFOAM® and OpenCFD® trade marks. diff --git a/docs/config.md b/docs/config.md index 584b458f..7f22c51a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -69,7 +69,11 @@ The `patches` specifies a list of the names of the OpenFOAM boundary patches tha participating in the coupled simulation. These need to be defined in the files included in the `0/` directory. The names of the interfaces (e.g., `Interface1`) are arbitrary and are not used. -The `locations` field is optional and its default value is `faceCenters` (with `faceCentres` also accepted), signifying that the interface mesh is defined on the cell face centers. The alternative option is `faceNodes`, which defines the mesh on the face nodes and is needed, e.g., for reading displacements in an FSI scenario. +The `locations` field is optional and its default value is `faceCenters` (with `faceCentres` also accepted), signifying that the interface mesh is defined on the cell face centers. An alternative option is `faceNodes`, which defines the mesh on the face nodes and is needed, e.g., for reading displacements in an FSI scenario. +The final type is `volumeCenters` (alternatively `volumeCentres`), which allows the user to couple over a volume using the cell centers of the domain. The user can also specify patches, which will be coupled additionally to the cells using the `faceCenters` mesh. +The `volumeCenters` location is currently implemented for fluid-fluid coupling (`Pressure` and `Velocity`) and conjugate heat transfer (`Temperature`). + +The `cellSets` field can be used to specify one or multiple coupling regions (defined by OpenFOAM `cellSets`) for volume coupling. The field can only be used with the `volumeCenters` location and it is optional. If no `cellSets` are specified, the full domain will be coupled. The values for `readData` and `writeData` for conjugate heat transfer @@ -213,36 +217,155 @@ solver displacementLaplacian; #### FF -The fluid-fluid coupling module supports reading and writing `Pressure`, `Velocity`, `PressureGradient`, and `VelocityGradient`. +The fluid-fluid coupling module supports reading and writing `Pressure`, `Velocity`, `PressureGradient`, `VelocityGradient`, `FlowTemperature`, `FlowTemperatureGradient`, `Alpha`, `AlphaGradient` and the face flux `Phi`. Similarly to the CHT module, you need a `fixedValue` boundary condition of the respective primary field in order to read and apply values, and a `fixedGradient` boundary condition of the respective gradient field in order to read and apply gradients. +Alternatively, the adapter also ships custom boundary conditions for pressure (`coupledPressure`) and velocity (`coupledVelocity`). These boundary conditions can be set on both sides of the coupling interface and can handle fluid flow in either direction. An initial `refValue` must be supplied to ensure convergence in the first time step. The adapter will overwrite the value afterwards. +If the OpenFOAM fields `phi` and `U` are given different names, they should be supplied to the boundary conditions as well. +The coupled boundary conditions act similar to the [`inletOutlet`](https://www.openfoam.com/documentation/guides/v2112/doc/guide-bcs-outlet-inlet-outlet.html) boundary conditions from OpenFOAM. However, the pressure gradient is calculated by OpenFOAM as for the [`fixedFluxExtrapolatedPressure`](https://www.openfoam.com/documentation/guides/v2112/api/classFoam_1_1fixedFluxExtrapolatedPressureFvPatchScalarField.html) boundary condition and thus no coupling of `PressureGradient` is required when using `coupledPressure`. + +```c++ +// File 0/U +interface +{ + type coupledVelocity; + refvalue uniform (0 0 0); + // phi phiName +} + +// File 0/p +interface +{ + type coupledPressure; + refValue $internalField; + // phi phiName + // U UName +} +``` + {% experimental %} The FF module is still experimental and the boundary conditions presented here have not been rigorously tested. -We already have reasons to believe that a `fixedGradient` can have [side-effects](https://github.com/precice/openfoam-adapter/issues/93) and may not lead to completely accurate results. {% endexperimental %} +`Alpha` refers to the phase variable used in e.g. the volume of fluid multiphase solver `interFoam`. + +When coupling face flux `Phi`, usually no specific boundary condition needs to be set. The coupled boundary values are therefore not persistent and may change within a timestep. + +### Volume coupling + +Besides surface coupling on the domain boundaries, the OpenFOAM adapter also supports coupling overlapping domains, which can be the complete domain, or regions of it. In contrast to surface coupling, though, reading volume data (source terms) requires a few additional configuration steps compared to writing data. + +In order to write volume data, it is enough to specify `volumeCenters` for the `locations` field. This will couple the whole internal field of the domain. Patches can be specified additionally, for surface coupling, or the list of patch names can be left empty. + +In order to read volume data (enforce source terms), it is necessary to use the [finite volume options](https://www.openfoam.com/documentation/guides/latest/doc/guide-fvoptions.html) (`fvOptions`) feature of OpenFOAM. Without this additional configuration, the values read in OpenFOAM in each time step would later be overwritten by OpenFOAM. +The `fvOptions` construct provides many different options for sources, but the [coded sources](https://www.openfoam.com/documentation/guides/latest/doc/guide-fvoptions-sources-coded.html) is a convenient way to describe source terms in configuration. + +Using a `codedSource` for reading fields and enforcing source terms in OpenFOAM would currently only work for `Velocity`. The adapter internally stores the received data in a separate velocity field, which the source term defined in OpenFOAM uses to update its own velocity field. For this reason, it is necessary to specify an alternative name for `U` in `preciceDict` when reading velocity in a volume-coupled scenario: + +```c++ +FF +{ + nameU U_vol; +}; +``` + +This essentially means two velocity variables are used: `U_vol` is the coupled velocity the adapter uses to carry over the desired value to OpenFOAM, and `U` is the variable OpenFOAM uses for its own velocity. In the `codedSource` you can explicitly set `U` to be equal to `U_vol`. Example from the [volume-coupled flow](https://precice.org/tutorials-volume-coupled-flow.html) tutorial: + +```c++ +// File constant/fvOptions + +codedSource +{ + type vectorCodedSource; + selectionMode cellSet; + cellSet box1; + + fields (U); + name sourceTime; + + codeConstrain //constrain + #{ + return; + #}; + + codeCorrect //correct + #{ + const labelList& cells = this->cells(); + const volVectorField& U_vol = mesh_.lookupObject("U_vol"); + for(auto cell : cells) + { + fld[cell].x() = U_vol[cell].x(); + } + #}; + + codeAddSup // source term + #{ + return; + #}; + + codeAddSupRho + #{ + return; + #}; +} +``` + +{% experimental %} +Reading volume-coupled variables in OpenFOAM is still experimental. This section simply contains suggestions about issues we have encountered and what has been found to work. +{% endexperimental %} + +#### Volume coupling over a domain region + +For reading values only over a region of the domain, we use the OpenFOAM [`cellSet` class](https://www.openfoam.com/documentation/guides/latest/api/classFoam_1_1cellSet.html) to define one or multiple volume coupling regions. You can define one or multiple `cellSets` in the `system/topoSetDict`: + +```C++ +actions +( + { + name box1; + type cellSet; + action new; + source boxToCell; + box (3.0 1.0 0.0) (3.5 1.5 1.0); + } +); +``` + +Additionally, list the `cellSets` you want to couple in the `preciceDict`: + +```C++ +Interface1 +{ + ... + cellSets (box1); + locations volumeCenters; +} +``` + +Before running the solver, and after preparing the mesh, execute [topoSet](https://www.openfoam.com/documentation/guides/latest/man/topoSet.html) to construct the overlapping region. + ### Load the adapter To load this adapter, you must include the following in the `system/controlDict` configuration file of the case: ```c++ +libs ("libpreciceAdapterFunctionObject.so"); functions { preCICE_Adapter { type preciceAdapterFunctionObject; - libs ("libpreciceAdapterFunctionObject.so"); } } ``` This directs the solver to use the `preciceAdapterFunctionObject` function object, which is part of the `libpreciceAdapterFunctionObject.so` shared library. -The name `preCICE_Adapter` can be arbitrary. +The name `preCICE_Adapter` can be arbitrary. It is important that the library is loaded outside the `functions` dictionary when you want to use the custom boundary conditions that we provide with the FF module. -If you are using other function objects in your simulation, add the preCICE adapter to the end of the list. The adapter will then be executed last, which is important, as the adapter also controls the end of the simulation. When the end of the simulation is detected, the adapter also triggers the `end()` method method of all function objects. +If you are using other function objects in your simulation, add the preCICE adapter to the end of the list. The adapter will then be executed last, which is important, as the adapter also controls the end of the simulation. When the end of the simulation is detected, the adapter also triggers the `end()` method of all function objects. *** @@ -343,6 +466,19 @@ rho rho [1 -3 0 0 0 0 0] 1; Notice that here, in contrast to the `CHT` subdict, we need to provide both the keyword (first `nu`) and the word name (second `nu`). We are working on bringing consistency on this. +#### Fluid-fluid coupling + +The FF module provides an option to correct the written velocity values for the face flux values `phi`. This may provide better mass consistency across the coupling interface when the used mesh is skewed. By default, this option is turned off. + +```c++ +FF +{ + fluxCorrection true; + namePhi phi; +} + +``` + ### Additional parameters in the adapter's configuration file Some optional parameters can allow the adapter to work with more solvers, whose type is not determined automatically, their fields have different names, or they do not work well with some features of the adapter. @@ -433,6 +569,12 @@ FF nameU U; // Pressure nameP p; + // Face flux (phi for most sovlers) + namePhi phi; + // Temperature + nameT T; + // Multiphase variable + nameAlpha alpha } ``` diff --git a/docs/get.md b/docs/get.md index a9d32dd4..5460106d 100644 --- a/docs/get.md +++ b/docs/get.md @@ -8,7 +8,8 @@ summary: "Get the code from GitHub and run ./Allwmake. If this fails, look into To build the adapter, you need to install a few dependencies and then execute the `Allwmake` script. 1. Install [a compatible OpenFOAM distribution](https://precice.org/adapter-openfoam-support.html). -2. Install [preCICE](https://precice.org/installation-overview.html). +2. Install [preCICE v3](https://precice.org/installation-overview.html). + * In case you need preCICE v2, please install an older version of the adapter ([v1.2.3](https://github.com/precice/openfoam-adapter/releases/tag/v1.2.3) was the last release to support preCICE v2). 3. [Download the latest release](https://github.com/precice/openfoam-adapter/releases/latest) for your OpenFOAM version. 4. Execute the build script: `./Allwmake`. * See and adjust the configuration in the beginning of the script first, if needed. @@ -16,6 +17,9 @@ To build the adapter, you need to install a few dependencies and then execute th The adapter also requires [pkg-config](https://linux.die.net/man/1/pkg-config) to [link to preCICE](https://precice.org/installation-linking.html). This is a very common dependency on Linux and is usually already installed. +You can set compile flags by either changing the `ADAPTER_PREP_FLAGS` variable in the `Allwmake` script, or directly setting the value of `ADAPTER_PREP_FLAGS` as an environment variable. +To do so, `export ADAPTER_PREP_FLAGS="-D -D"` before compiling the adapter. + Adding the `-DADAPTER_DEBUG_MODE` flag to the `ADAPTER_PREP_FLAGS` activates additional debug messages. You may also change the target directory or specify the number of threads to use for the compilation. See the comments in `Allwmake` for more. Adding the `-DADAPTER_ENABLE_TIMINGS` flag to the `ADAPTER_PREP_FLAGS` activates time measurements for several regions of the adapter, printed at the end of the simulation output (available since v1.2.0). @@ -96,3 +100,14 @@ This is a common problem e.g. when installing dependencies in non-system directo ### Rellocation-related errors Make sure to build both preCICE as a shared library (i.e. `.so`, not `.a`). + +### Undefined symbols from FFTW + +When building the adapter, it may fail to at the very end, reporting the following in the `ldd.log`: + +```text +undefined symbol: fftw_taint (/lib/x86_64-linux-gnu/libfftw3_mpi.so.3) +undefined symbol: fftw_join_taint (/lib/x86_64-linux-gnu/libfftw3_mpi.so.3) +``` + +This seems to always be related to building OpenFOAM from source, while also already having FFTW (an OpenFOAM dependency) installed. Removing FFTW from the `ThirdParty` directory of the OpenFOAM source code, and running `Allwmake` in OpenFOAM (and then also in the adapter) should help. This should also be very fast, as it will only relink, not rebuild. diff --git a/docs/openfoam-support.md b/docs/openfoam-support.md index 79e2caf2..fb8fc0df 100644 --- a/docs/openfoam-support.md +++ b/docs/openfoam-support.md @@ -7,14 +7,14 @@ summary: Recent OpenFOAM.com versions work out-of-the-box. Recent OpenFOAM.org v ## How to get OpenFOAM -The easiest way to start is to get binary packages for your Linux distribution. For example, to [get OpenFOAM v2212 on Ubuntu](https://develop.openfoam.com/Development/openfoam/-/wikis/precompiled/debian#precompiled-packages-debianubuntu): +The easiest way to start is to get binary packages for your Linux distribution. For example, to [get OpenFOAM v2312 on Ubuntu](https://develop.openfoam.com/Development/openfoam/-/wikis/precompiled/debian#precompiled-packages-debianubuntu): ```bash # Add the signing key, add the repository, update: wget -q -O - https://dl.openfoam.com/add-debian-repo.sh | sudo bash -# Install OpenFOAM v2212: -sudo apt-get install openfoam2212-dev +# Install OpenFOAM v2312: +sudo apt-get install openfoam2312-dev ``` As these steps change your `.profile`, you need to log out and in again to make OpenFOAM fully discoverable. @@ -26,7 +26,8 @@ OpenFOAM is a project with long history and many forks, of which we try to suppo We provide version-specific [release archives](https://github.com/precice/openfoam-adapter/releases/latest) and respective Git branches for: - OpenCFD / ESI (openfoam.com) - main focus: - - [OpenFOAM v1812-v2212](https://github.com/precice/openfoam-adapter) or newer + - [OpenFOAM v1812-v2312](https://github.com/precice/openfoam-adapter) or newer + - OpenFOAM v2212 and newer is only supported since v1.2.2 of the adapter. - [OpenFOAM v1612-v1806](https://github.com/precice/openfoam-adapter/tree/OpenFOAMv1806) (not tested) - OpenFOAM Foundation (openfoam.org) - secondary, consider experimental: - [OpenFOAM 10](https://github.com/precice/openfoam-adapter/tree/OpenFOAM10) @@ -34,6 +35,7 @@ We provide version-specific [release archives](https://github.com/precice/openfo - Same limitations as for OpenFOAM 9. - [OpenFOAM 9](https://github.com/precice/openfoam-adapter/tree/OpenFOAM9) - Rename `solver` to `motionSolver` in `constant/dynamicMeshDict`. + - Modify also `residualControl` to `outerCorrectorResidualControl` in `system/fvSolution`. - Limitations in adjustable time step size ([#261](https://github.com/precice/openfoam-adapter/issues/261)). - [OpenFOAM 8](https://github.com/precice/openfoam-adapter/tree/OpenFOAM8) - [OpenFOAM 7](https://github.com/precice/openfoam-adapter/tree/OpenFOAM7) diff --git a/preciceAdapterFunctionObject.C b/preciceAdapterFunctionObject.C index 3dea534a..92a4cd4e 100644 --- a/preciceAdapterFunctionObject.C +++ b/preciceAdapterFunctionObject.C @@ -51,7 +51,7 @@ Foam::functionObjects::preciceAdapterFunctionObject::preciceAdapterFunctionObjec adapter_(runTime, mesh_) { -#if (defined OPENFOAM_PLUS && (OPENFOAM_PLUS >= 1712)) || (defined OPENFOAM && (OPENFOAM >= 1806)) +#if (defined OPENFOAM && (OPENFOAM >= 1712)) || (defined OPENFOAM_PLUS && (OPENFOAM_PLUS >= 1712)) // Patch for issue #27: warning "MPI was already finalized" while // running in serial. This only affects openfoam.com, while initNull() // does not exist in openfoam.org. diff --git a/tools/create-release-archives.sh b/tools/create-release-archives.sh new file mode 100755 index 00000000..7287ffae --- /dev/null +++ b/tools/create-release-archives.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Execute this script from the top-level directory (./tools/create-release-archives.sh) + +set -u + +remote_name=origin +adapter_version="v1.3.0" + +# Declare branch names for which archives will be created +declare -a branches=("master" "OpenFOAMv1806" "OpenFOAM10" "OpenFOAM9" "OpenFOAM8" "OpenFOAM7" "OpenFOAM6" "OpenFOAM5") + +mkdir -p release-archives +for i in "${branches[@]}" + do + archive_name=openefoam-adapter-"${adapter_version}"-"${i}" + git archive --format=tar.gz --prefix="${archive_name}"/ "${remote_name}"/"${i}" >"release-archives/${archive_name}".tar.gz +done diff --git a/tools/release_pull_request_template.md b/tools/release_pull_request_template.md index 1e7a2736..c838b823 100644 --- a/tools/release_pull_request_template.md +++ b/tools/release_pull_request_template.md @@ -86,5 +86,6 @@ master <-- OpenFOAM4 <-- OpenFOAM5 <-- OpenFOAM6 <-- OpenFOAM7 <-- ... <-- OpenF - [ ] Update external documentation (tutorials, website), e.g., regarding the adapter or OpenFOAM version. - [ ] Quickstart - [ ] Update the VM provisioning scripts, if needed (e.g., OpenFOAM version) +- [ ] Update the [Spack package](https://github.com/kjrstory/spack/blob/develop/var/spack/repos/builtin/packages/of-precice/package.py) - [ ] Update this release checklist (`tools/release_pull_request_template.md`) - [ ] Advertise and celebrate! :tada: :beers: